首页 > 代码库 > BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]

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;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];        now++;    }}    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]);    int ans=0;    for(int i=1;i<=now;i++) if(a[i][n+1]) ans++;    printf("%d",ans);}

 

BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]