POJ1830 开关问题【高斯消元法】
2015-09-14 16:50
337 查看
题目连接:
http://poj.org/problem?id=1830
题目大意:
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的
时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态
如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最
后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。现
在计算有多少种可以达到指定状态的方法。
解题思路:
对于每个灯有改变或者不改变两种状态,用 1、0 来表示。构造矩阵 A[][],A[i][j] 表示操
作第 i 个开关,第 j 个开关的状态也跟着改变。那么就可以建立 N 个方程组,有开关间
的关系可以确定方程组各变元的系数。N 个开关的开始状态和最终状态的亦或,作为方
程组的常数值,然后用高斯消元法解方程组,求解出是否有解。
无解输出 Oh,it's impossible~!! ,有解计算出变元数目,因为每个变元都有0 和 1两种
可能,所以结果为 1 << ans。
AC代码:
http://poj.org/problem?id=1830
题目大意:
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的
时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态
如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最
后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。现
在计算有多少种可以达到指定状态的方法。
解题思路:
对于每个灯有改变或者不改变两种状态,用 1、0 来表示。构造矩阵 A[][],A[i][j] 表示操
作第 i 个开关,第 j 个开关的状态也跟着改变。那么就可以建立 N 个方程组,有开关间
的关系可以确定方程组各变元的系数。N 个开关的开始状态和最终状态的亦或,作为方
程组的常数值,然后用高斯消元法解方程组,求解出是否有解。
无解输出 Oh,it's impossible~!! ,有解计算出变元数目,因为每个变元都有0 和 1两种
可能,所以结果为 1 << ans。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN = 40; int Equ,Var; int A[MAXN][MAXN]; int X[MAXN]; bool FreeX[MAXN]; int FreeNum; void Debug() { for(int i = 0; i < Equ; ++i) { for(int j = 0; j < Var+1; ++j) cout << A[i][j] << ' '; cout << endl; } } int GCD(int a,int b) { if(b == 0) return a; return GCD(b,a%b); } int LCM(int a,int b) { return a / GCD(a,b) * b; } int Gauss() { int i,j,k; int MaxRow; int col = 0; int Lcm; int ta,tb; int temp; int FreeXNum; int FreeIndex; for(k = 0; k < Equ && col < Var; ++k,++col) { MaxRow = k; for(i = k+1; i < Equ; ++i) { if(abs(A[i][col]) > abs(A[MaxRow][col])) MaxRow = i; } if(MaxRow != k) { for(i = k; i < Var+1; ++i) swap(A[k][i],A[MaxRow][i]); } if(A[k][col] == 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 + 2) % 2; } } } for(i = k; i < Equ; ++i) if(A[i][col]) return -1; if(k < Var) return Var - k; for(i = Var-1; i >= 0; --i) { temp = A[i][Var] % 2; for(j = i+1; j < Var; ++j) if(A[i][j]) temp = (temp - A[i][j]*X[j]%2 + 2) % 2; if(temp % A[i][i]) return -2; X[i] = temp / A[i][i] % 2; } return 0; } void Init(int N) { memset(A,0,sizeof(A)); memset(X,0,sizeof(X)); Equ = Var = N; for(int i = 0; i < N; ++i) A[i][i] = 1; } int Start[MAXN],End[MAXN]; int main() { int T,N; scanf("%d",&T); while(T--) { 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]); Init(N); int u,v; while(~scanf("%d%d",&u,&v) && (u||v)) { A[v-1][u-1] = 1; } for(int i = 0; i < N; ++i) A[i] = (Start[i] - End[i] + 2) % 2; int ans = Gauss(); if(ans == -1) printf("Oh,it's impossible~!!\n"); else printf("%d\n",(1<<ans)); } return 0; }
相关文章推荐
- 第三周项目3程序的多文件组织
- 查看Win7系统电源使用状况的快捷方法
- xHTML究竟有多少个标签?
- 巧用ViewInject
- File对文件的操作,创建、复制、删除、移动和打开文件的静态方法
- xib与storyBoard中控件属性设置问题
- 【剑指offer】统计一个数字在排序数组中出现的次数
- 加州理工大学公开课:机器学习与数据挖掘_线性模型 II(第IX类)
- git revert 和 git reset的区别
- 第二周实践项目(3)~体验复杂度
- LoadRunner脚本回放问题及解决5
- 第二周项目3复杂度体验1 两种排序算法的运行时间
- linux 下定时器的实现
- ANSI和UNICODE
- 网络连接之-xUtils框架(第三方通信框架)介绍(一)
- arguments.callee 调用自身
- 内容绘制到Bitmap上不成功警示
- Android(java)学习笔记247:ContentProvider使用之利用ContentProvider备份和还原手机短信(掌握)
- 第2周项目3 体验复杂度(1)两种排序算法的运行时间
- 创建一个WCF Rest Service