BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]
题意:
经典灯问题,求最少次数
本题数据不水,必须要暴搜自由元的取值啦
想了好久
然而我看到网上的程序都没有用记录now的做法,那样做遇到自由元应该可能会丢解吧...?
我的做法是把自由元保存下来,枚举的时候只枚举自由元
但这样没法最优性剪枝了
于是枚举的时候还是从n到1枚举,到i时如果i是主元这时候i的值已经可以算出来了,这样就可以最优性剪枝了
但注意主元i你不能用i这个方程,而要保存pivot[i]为i用了哪个方程
然后一个伪贪心策略是自由元先搜0
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bitset> using namespace std; const int N=40,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,u,v; bitset<N> a[N]; int fe[N],now,pivot[N]; void Gauss(){ now=1; for(int i=1;i<=n;i++){ int j=now;//printf("hi %d %d %d\n",i,now,a[now][i]==1); while(j<=n&&!a[j][i]) j++; if(j==n+1) {fe[++fe[0]]=i;continue;} if(j!=now) swap(a[now],a[j]); for(int j=1;j<=n;j++) if(j!=now&&a[j][i]) a[j]^=a[now]; pivot[i]=now;//printf("pivot %d\n",i); now++; } } int val[N],tot,ans=INF; void pri(){ puts("free"); for(int i=1;i<=fe[0];i++) printf("fe %d %d %d\n",i,fe[i],val[i]); puts("end"); } int fir=1; void dfs(int d){ //printf("dfs %d %d\n",d,tot); if(tot>=ans) return; if(d==0) ans=min(ans,tot);//if(fir==1) printf("tot %d\n",tot),pri(),fir=0;} else if(pivot[d]){//printf("d %d\n",d); int i=pivot[d]; int _=a[i][n+1]; for(int j=1;j<=fe[0];j++) if(a[i][fe[j]]) _^=val[fe[j]]; tot+=_; dfs(d-1); tot-=_; }else{ val[d]=0; dfs(d-1); val[d]=1; tot++; dfs(d-1); tot--; } } int main(){ //freopen("in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++) u=read(),v=read(),a[u][v]=a[v][u]=1; for(int i=1;i<=n;i++) a[i][n+1]=a[i][i]=1; Gauss(); //for(int i=1;i<=n;i++) printf("a %d %d\n",i,a[i][n+1]==1); //for(int i=1;i<=fe[0];i++) printf("fe %d %d\n",i,fe[i]); dfs(n); printf("%d",ans); }
Copyright:http://www.cnblogs.com/candy99/