luogu 2962 [USACO09NOV]燈Lights
阿新 • • 發佈:2019-05-05
.cn sta names spa clas space scanf 但是 裏的
還是高斯消元解異或方程組
如果這個你不會,請看這裏
現在假定你已經會這個東西了
那麽我們就可以構造模型了
首先有一個很顯然的結論:一個開關至多只需要按一次!(因為按兩次等於不按,按三次等於按一次....)
我們設一盞燈開的狀態為1,關的狀態為0,那麽我們的目標就是把所有燈的狀態都改成1
那麽能影響到一盞燈的因素就是所有關聯他的開關以及他本身
那麽我們設每個開關的狀態為$x_i$,與這盞燈有關的開關集合為S,那麽一個燈最後的要求就是
$\sum_{i∈S}x_i==1$(這裏的$\sum$表示異或和)
那麽就是異或方程組了,用高斯消元解之即可
但是會有自由元的問題,所以我們要用dfs枚舉每個自由元的狀態,使得取得1的x數量最小,註意剪枝即可
然後就結束了
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <vector> using namespace std; int a[45][45]; int n,m; vector <int> v[45]; void Gauss() {for(int i=1;i<=n;i++) { int temp=i; while(!a[temp][i]&&temp<=n)temp++; if(temp>n)continue; if(temp!=i)for(int j=i;j<=n+1;j++)swap(a[i][j],a[temp][j]); for(int j=1;j<=n;j++)if(a[j][i]&&j!=i)for(int k=i;k<=n+1;k++)a[j][k]^=a[i][k]; } }int ans=0x3f3f3f3f; void dfs(int dep,int sum) { if(sum>=ans)return; if(!dep){ans=sum;return;} if(a[dep][dep])dfs(dep-1,sum+a[dep][n+1]); else { if(a[dep][n+1])return; dfs(dep-1,sum); for(int j=dep-1;j>=1;j--)a[j][n+1]^=a[j][dep]; dfs(dep-1,sum+1); for(int j=dep-1;j>=1;j--)a[j][n+1]^=a[j][dep]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); v[x].push_back(y),v[y].push_back(x); } for(int i=1;i<=n;i++) { for(int j=0;j<v[i].size();j++)a[i][v[i][j]]=1; a[i][i]=a[i][n+1]=1; } Gauss(); dfs(n,0); printf("%d\n",ans); return 0; }
luogu 2962 [USACO09NOV]燈Lights