Lanterns
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1472 Accepted Submission(s): 581
Alice wants to change the state of the lanterns to some specific configurations and she knows that pushing a switch more than once is pointless. Help Alice to find out the number of ways she can achieve the goal. Two ways are different if and only if the sets (including the empty set) of the switches been pushed are different.
The first line of each test case contains an integer n (1<=n<=50) and m (1<=m<=50).
Then m lines follow. Each line contains an integer k (k<=n) indicating the number of lanterns this switch controls.
Then k integers follow between 1 and n inclusive indicating the lantern controlled by this switch.
The next line contains an integer Q (1<=Q<=1000) represent the number of queries of this test case.
Q lines follows. Each line contains n integers and the i-th integer indicating that the state (1 for on and 0 for off) of the i-th lantern of this query.
Please follow the format of the sample output.
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn = 110;
const int mod = 2;
int a[maxn][maxn];//增廣矩陣
int b[maxn][maxn];
int x[maxn];//解集
bool free_x[maxn];//標記是否是不確定的變元
int gcd(int a,int b)
{
return a == 0?b:gcd(b%a,a);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);//先除後乘防溢出
}
// 高斯消元法解方程組(Gauss-Jordan elimination).(-2表示有浮點數解,但無整數解,
//-1表示無解,0表示唯一解,大於0表示無窮解,並返回自由變元的個數)
//有equ個方程,var個變元。增廣矩陣行數爲equ,分別爲0到equ-1,列數爲var+1,分別爲0到var.
int Gauss(int equ,int var)
{
int i,j,k;
int max_r;// 當前這列絕對值最大的行.
int col;//當前處理的列
int ta,tb;
int LCM;
int temp;
int free_x_num;
int free_index;
// for(int i=0;i<=var;i++)
// {
// x[i]=0;
// free_x[i]=true;
// }
//轉換爲階梯陣.
col=0; // 當前處理的列
for(k = 0;k < equ && col < var;k++,col++)
{// 枚舉當前處理的行.
// 找到該col列元素絕對值最大的那行與第k行交換.(爲了在除法時減小誤差)
max_r=k;
for(i=k+1;i<equ;i++)
{
if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
}
if(max_r!=k)
{// 與第k行交換.
for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
}
if(a[k][col]==0)
{// 說明該col列第k行以下全是0了,則處理當前行的下一列.
k--;
continue;
}
for(i=k+1;i<equ;i++)
{// 枚舉要刪去的行.
if(a[i][col])
{
LCM = lcm(abs(a[i][col]),abs(a[k][col]));
ta = LCM/abs(a[i][col]);
tb = LCM/abs(a[k][col]);
if(a[i][col]*a[k][col]<0)tb=-tb;//異號的情況是相加
for(j=col;j<var+1;j++)
{
a[i][j] = ((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod;//如果不是同模取餘則改爲a[i][j] = (a[i][j]*ta-a[k][j]*tb;
}
}
}
}
// 1. 無解的情況: 化簡的增廣陣中存在(0, 0, ..., a)這樣的行(a != 0).
for (i = k; i < equ; i++)
{ // 對於無窮解來說,如果要判斷哪些是自由變元,那麼初等行變換中的交換就會影響,則要記錄交換.
if (a[i][col]) return -1;
}
// 2. 無窮解的情況: 在var * (var + 1)的增廣陣中出現(0, 0, ..., 0)這樣的行,即說明沒有形成嚴格的上三角陣.
// 且出現的行數即爲自由變元的個數.
if (k < var)
{
//首先,自由變元有var - k個,即不確定的變元至少有var - k個.
// for (i = k - 1; i >= 0; i--)
// {
// // 第i行一定不會是(0, 0, ..., 0)的情況,因爲這樣的行是在第k行到第equ行.
// // 同樣,第i行一定不會是(0, 0, ..., a), a != 0的情況,這樣的無解的.
// free_x_num = 0; // 用於判斷該行中的不確定的變元的個數,如果超過1個,則無法求解,它們仍然爲不確定的變元.
// for (j = 0; j < var; j++)
// {
// if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
// }
// if (free_x_num > 1) continue; // 無法求解出確定的變元.
// // 說明就只有一個不確定的變元free_index,那麼可以求解出該變元,且該變元是確定的.
// temp = a[i][var];
// for (j = 0; j < var; j++)
// {
// if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
// }
// x[free_index] = temp / a[i][free_index]; // 求出該變元.
// free_x[free_index] = 0; // 該變元是確定的.
// }
return var - k; // 自由變元有var - k個.
}
// 3. 唯一解的情況: 在var * (var + 1)的增廣陣中形成嚴格的上三角陣.
// 計算出Xn-1, Xn-2 ... X0.
//需要解得時候就用下面的循環來解。
// for (i = var - 1; i >= 0; i--)
// {
// temp = a[i][var];
// for (j = i + 1; j < var; j++)
// {
// if (a[i][j] != 0) temp = ((temp - a[i][j]*x[j])%mod+mod)%mod;//temp -= a[i][j] * x[j];
// }
// while(temp % a[i][i] != 0) temp+=mod;//如果不是同模取餘,則temp % a[i][i] != 0時產生浮點數解
// x[i] = (temp / a[i][i])%mod;
// if(x[i]<0)x[i]+=mod;
// }
return 0;
}
int main()
{
int i, j;
int n,m,var;
int t,kase = 1;
scanf("%d",&t);
while (t--)
{
memset(b,0,sizeof(b));
scanf("%d%d", &n, &var);
for(int i = 0;i < var;i++)
{
int num;
scanf("%d",&num);
for(int j = 0;j < num;j++)
{
int nn;
scanf("%d",&nn);
b[nn-1][i] = 1;
}
}
scanf("%d",&m);
printf("Case %d:\n",kase++);
while(m--)
{
memcpy(a,b,sizeof(b));
for(int i = 0;i < n;i++)
{
scanf("%d",&a[i][var]);
}
int ans = Gauss(n,var);
if(ans == -1)
printf("0\n");
else if(ans == 0)
printf("1\n");
else
printf("%I64d\n",1LL<<ans);
}
}
return 0;
}