POJ 1830 开关问题(高斯消元)
2016-08-06 10:46
302 查看
Description
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
Input
输入第一行有一个数K,表示以下有K组测试数据。
每组测试数据的格式如下:
第一行 一个数N(0 < N < 29)
第二行 N个0或者1的数,表示开始时N个开关状态。
第三行 N个0或者1的数,表示操作结束后N个开关的状态。
接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。
Output
如果有可行方法,输出总数,否则输出“Oh,it’s impossible~!!” 不包括引号
Sample Input
2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0
Sample Output
4
Oh,it’s impossible~!!
Solution
将是否操作某个开关看作一个变量,问题转化为求一个n*n的模2线性方程组解的个数,统计自由变元个数即可,假设自由变元个数有cnt个,那么每确定一组自由变元的取值就确定一组解,答案就是2^cnt
Code
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
Input
输入第一行有一个数K,表示以下有K组测试数据。
每组测试数据的格式如下:
第一行 一个数N(0 < N < 29)
第二行 N个0或者1的数,表示开始时N个开关状态。
第三行 N个0或者1的数,表示操作结束后N个开关的状态。
接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。
Output
如果有可行方法,输出总数,否则输出“Oh,it’s impossible~!!” 不包括引号
Sample Input
2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0
Sample Output
4
Oh,it’s impossible~!!
Solution
将是否操作某个开关看作一个变量,问题转化为求一个n*n的模2线性方程组解的个数,统计自由变元个数即可,假设自由变元个数有cnt个,那么每确定一组自由变元的取值就确定一组解,答案就是2^cnt
Code
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<map> #include<set> #include<ctime> using namespace std; //高斯消元法解模线性方程组 #define maxn 33 int a[maxn][maxn];//增广矩阵 int x[maxn];//解集 bool free_x[maxn];//标记是否是不确定的变元 int gcd(int a,int b) { return b?gcd(b,a%b):a; } int lcm(int a,int b) { return a/gcd(a,b)*b; } // 高斯消元法解方程组 //-2表示有浮点数解,但无整数解 //-1表示无解 //0表示唯一解 //大于0表示无穷解,并返回自由变元的个数 //有equ个方程,var个变元 //增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var. int Gauss(int equ,int var,int mod) { 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]!=0) { 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; } } } } //无解的情况 for(i=k;i<equ;i++) { if(a[i][col]!=0) return -1; } // 无穷解的情况 if(k<var) { //自由变元有var-k个,即不确定的变元至少有var-k个. for(i=k-1;i>=0;i--) { 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]%mod; temp=(temp%mod+mod)%mod; } x[free_index]=(temp/a[i][free_index])%mod;//求出该变元. free_x[free_index]=0;//该变元是确定的. } return var-k; //自由变元有var-k个. } //唯一解的情况 for(i=var-1;i>=0;i--) { temp=a[i][var]; for(j=i+1;j<var;j++) { if(a[i][j]!=0) temp-=a[i][j]*x[j]; temp=(temp%mod+mod)%mod; } while(temp%a[i][i]!=0) temp+=mod; x[i]=(temp/a[i][i])%mod; } return 0; } int T,n,start[maxn],end[maxn]; int main() { scanf("%d",&T); while(T--) { memset(a,0,sizeof(a)); scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&start[i]); for(int i=0;i<n;i++)scanf("%d",&end[i]); int x,y; while(scanf("%d%d",&x,&y),x||y)a[y-1][x-1]=1; for(int i=0;i<n;i++)a[i][i]=1,a[i] =start[i]^end[i]; int ans=Gauss(n,n,2); if(ans==-1)printf("Oh,it's impossible~!!\n"); else printf("%d\n",(1<<ans)); } return 0; }
相关文章推荐
- poj 1830 开关问题(高斯消元)
- POJ 1830 开关问题 高斯消元 异或方程
- POJ 1830 开关问题 (01高斯消元)
- POJ 1830 开关问题 高斯消元
- poj 1830 开关问题(高斯消元)
- poj 1830 开关问题 高斯消元
- POJ-1830 开关问题 高斯消元
- 【高斯消元】【poj 1830】开关问题
- POJ 1830 开关问题 (高斯消元)
- POJ 1830 开关问题 高斯消元
- poj1830 开关问题解题报 <高斯消元>
- poj 1830 开关问题 高斯消元
- POJ 1830 开关问题(高斯消元)
- poj 1830 开关问题 高斯消元
- POJ 1830 开关问题 高斯消元求自由变元
- poj 1830 开关问题 (高斯消元)
- POJ 开关问题 1830【高斯消元求矩阵的秩】
- POJ 1830 开关问题(高斯消元)
- POJ 1830 开关问题 高斯消元
- 开关问题 POJ 1830(高斯消元求解的个数)