POJ 1830 开关问题(高斯消元法)

来源:互联网 发布:大富翁3.4棋牌源码 编辑:程序博客网 时间:2024/04/30 08:43

解题思路:
由于对于每一个开关最多改变一次,那么对于每一个开关,只有改变与不改变两种操作,设改变操作为1,不改变操作为0,那么对开关的操作可以用一个n维向量x⃗ T=(x1,x2,⋯,xn),其中xi=0或者1。
我们需要知道初始状态经过某次操作之后的状态,并拿它与目标状态比较。我们知道,对于开关i,除了对i的操作xi会影响其状态,与其相关联的开关j的操作xj也会影响其状态。显然,只有当开关j影响开关i并且xj=1(即改变开关j),才会使开关i改变。令aij表示开关j是否影响开关i,影响为1,不影响为0,则aijxj表示开关j是否改变开关i,改变为1,不改变为0。若定义aii=1,那么∑n,j=1(aijxj)就表示开关i被改变的次数。显然,改变次数为奇数,则说明改变初始状态,反之不变。若用向量b⃗ T=(b1,b2,⋯,bn)表示初始状态与目标状态之间的关系,bi表示开关i的目标与初始状态是否一致,1表示不一致,0表示一致,则方程∑n,j=1(aijxj)≡bi(mod2)表示将开关i改变为目标状态。由于模运算的性质,我们可以先对线性方程组Ax=b进行初等行变换再对两边取模。由于只需要求可行方案数(即方程解的个数),而并不关心解本身,我们仅仅求得线性方程组系数矩阵与增广矩阵的秩即可。若r(A) < r(A,b)则方程无解(无可行方案),若r(A)=r(A,b)=n则方程有唯一解(有一种方案),若r(A)=r(A,b) < n,由于解向量中自由变元仅有两种取值(0或1),可行方案数为2r(A,b)−r(A)。

#include<iostream>#include<cmath>#include<algorithm>#include<cstring>using namespace std;int ab[50][50], st[50], en[50];inline int gauss(int n){    int i = 0, j = 0, k;    while (j < n)    {        int id = i;        for (k = i + 1; k < n; k++)            if (abs(ab[k][j]) > abs(ab[id][j]))                id = k;        if (id != i)        {            for (k = j; k <= n; k++)                swap(ab[i][k], ab[id][k]);        }        if (ab[i][j] == 0) { j++; continue; }        for (k = i + 1; k < n; k++)        {            if (ab[k][j] == 0) continue;            for (int l = j; l <= n; l++)                ab[k][l] = ab[k][l] ^ ab[i][l];        }        i++, j++;    }    for (int k = i; k < n; k++)         if (ab[k][n] != 0) return -1;    return 1 << (n - i);}int main(){    int T;    cin >> T;    while (T--)    {        int n;        cin >> n;        for (int i = 0; i < n; i++) cin >> st[i];        for (int i = 0; i < n; i++) cin >> en[i];        memset(ab, 0, sizeof(ab));        for (int i = 0; i < n; i++)            ab[i][i] = 1, ab[i][n] = st[i] ^ en[i];        int I, J;        cin >> I >> J;        while (I)        {            ab[J - 1][I - 1] = 1;            cin >> I >> J;        }        int ans = gauss(n);        if (ans == -1)              cout << "Oh,it's impossible~!!\n";        else             cout << ans << endl;    }    return 0;}
1 0
原创粉丝点击