POJ - 1830:开关问题 (开关问题-高斯消元-自由元)

pro:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

sol:即求自由元的个数,答案是pow(2,自由元)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int a[30][30],ans[30];
int Guass(int N)
{
    int res=0;
    rep(i,0,N-1){
        int mark=i;
        rep(j,i+1,N-1) if(abs(a[j][i])>abs(a[mark][i])) mark=j;
        if(mark!=i) rep(j,0,N) swap(a[i][j],a[mark][j]);
        if(!a[i][i]){ res++; continue;} //自由元
        rep(j,i+1,N){
           if(!a[j][i]) continue;
           rep(k,i,N){
               a[j][k]^=a[i][k];
           }
        }
    }
    for(int i=N-1;i>=0;i--){
        if(!a[i][i]&&a[i][N]) return -1;//无解
        ans[i]=a[i][N]&a[i][i];
        rep(j,0,i-1) a[j][N]^=(a[j][i]&ans[i]);
    }
    return 1<<res;
}
int s[300],t[300],res;
int main()
{
    int T,N,u,v;
    scanf("%d",&T);
    while(T--){
        memset(a,0,sizeof(a));
        scanf("%d",&N);
        rep(i,0,N-1) scanf("%d",&s[i]);
        rep(i,0,N-1) scanf("%d",&t[i]);
        rep(i,0,N-1) a[i][N]=s[i]^t[i],a[i][i]=1;
        while(~scanf("%d%d",&u,&v)&&u+v!=0){
            a[v-1][u-1]=1; //二者不要写反
        }
        int res=Guass(N);
        if(res==-1) puts("Oh,it's impossible~!!");
        else printf("%d\n",res);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/10764284.html