1. 程式人生 > >luogu 2962 [USACO09NOV]燈Lights

luogu 2962 [USACO09NOV]燈Lights

.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