<h2><pre name="code" class="cpp"><span style="font-size:18px;">高斯消元。</span>
<span style="font-size:18px;">先送上参考学习网址:</span>
<span style="font-size:18px;"><a target=_blank href="http://www.cppblog.com/menjitianya/archive/2014/06/08/207226.html" target="_blank">http://www.cppblog.com/menjitianya/archive/2014/06/08/207226.html</a></span>
<span style="font-size:18px;"><a target=_blank href="http://blog.sina.com.cn/s/blog_62ebd4410100h2qf.html" target="_blank">http://blog.sina.com.cn/s/blog_62ebd4410100h2qf.html</a></span>
<span style="font-size:18px;">文章中或许有瑕疵,仔细看看就知道了。
</span>
</pre><pre name="code" class="cpp">
<span style="font-size:18px;">关于我的代码,这里有几点说明(特别是第二点):</span>
<span style="font-size:18px;">1.swap函数:两个数的异或满足交换律,代入验证即可</span>
<span style="font-size:18px;">2.cal函数中i=0,j=0开始的循环消项函数中为什么可以用异或运算代替正常的加减运算:</span>
<span style="font-size:18px;">假设矩阵a,b(由上到下,a<b)两行,map[a][j]==1,map[b][j]==1:为形成上三角矩阵,要用map[a][j]消去map[b][j],一般情况下,显然a行系数全部乘上-1,再与b行相加,消去map[b][j],但这会导致b行系数中出现-1项(假设-1对应方程中的-x2项)。</span>
<span style="font-size:18px;">此时可以将b行中的-1项转换为系数为1项。注意,矩阵每一行数对应的每一个方程的系数,而题中方程为模线性方程(mod 2),只要在b行代表的方程两边加上2*(x2),由余数定理知该操作不会影响最终解,也将矩阵中-1项转换为1项。</span>
<span style="font-size:18px;">类似的,也就是说每一次消项操作只会使矩阵中的数变为0或1,那么就会与异或联系在一起:</span>
<span style="font-size:18px;">(1)若map[a][k]==0,显然该项乘以-1,再加上map[b][k],是不会影响map[b][k]的,相当于0^map[b][k]=map[b][k];</span>
<span style="font-size:18px;">(2)若map[a][k]==1,该项乘以-1,若map[b][k]==1,则map[a][k]+map[b][k]==0,相当于1^map[b][k]=0;</span>
<span style="font-size:18px;">(3)若map[a][k]==1,该项乘以-1,若map[b][k]==0,则map[a][k]+map[b][k]==-1(该项系数可以转换为1),相当于1^map[b][k]=1.</span>
<span style="font-size:18px;">综合上述,消项结果就相当于map[a][k]^map[b][k]的结果</span>
<span style="font-size:18px;"></span><pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
short sta[35],end[35],map[35][35];
int n;
void swap(int &a,int &b){
a=a^b;
b=a^b;
a=a^b;
}
int cal(){
int i,j,k,l;
for(i=0,j=0;j<n;){//两种情况退出:最后行的倒数第二格为0或不为0
int id=i;
for(l=i+1;l<n;l++){
if(map[l][j]>map[id][j])
id=l;
}
if(map[id][j]==0){
j++;
continue;
}
if(id!=i){
for(l=j;l<=n;l++){
swap(map[id][l],map[i][l]);
}
}
for(l=i+1;l<n;l++){//消项
if(!map[l][j]) continue;
for(k=j;k<=n;k++){
map[l][k]=map[l][k]^map[i][k];//错将i写为id,WA
//原来相消会出现系数为-1的项,那么在等式两边加上该项系数为1时的两倍,方程解不变
}
}
i++;j++;
}
for(k=i;k<n;k++)
if(map[k][n])
return -1;
return 1<<(n-i);
}
int main(){
//freopen("D:\\INPUT.txt","r", stdin);
int k;
cin>>k;
while(k--){
scanf("%d",&n);
int i,j,l;
for(i=0;i<n;i++) scanf("%d",&sta[i]);
for(i=0;i<n;i++) scanf("%d",&end[i]);
memset(map,0,sizeof(map));
while(scanf("%d%d",&j,&l),j||l){
map[l-1][j-1]=1;
}
for(i=0;i<n;i++){
map[i][n]=sta[i]^end[i];
map[i][i]=1;
}
int ans=cal();
if(ans==-1){
cout<<"Oh,it's impossible~!!"<<endl;
}
else{
cout<<ans<<endl;
}
}
return 0;
}
<h2><pre name="code" class="cpp"><span style="font-size:18px;">高斯消元。</span>
<span style="font-size:18px;">先送上参考学习网址:</span>
<span style="font-size:18px;"><a target=_blank href="http://www.cppblog.com/menjitianya/archive/2014/06/08/207226.html" target="_blank">http://www.cppblog.com/menjitianya/archive/2014/06/08/207226.html</a></span>
<span style="font-size:18px;"><a target=_blank href="http://blog.sina.com.cn/s/blog_62ebd4410100h2qf.html" target="_blank">http://blog.sina.com.cn/s/blog_62ebd4410100h2qf.html</a></span>
<span style="font-size:18px;">文章中或许有瑕疵,仔细看看就知道了。
</span>
</pre><pre name="code" class="cpp">
<span style="font-size:18px;">关于我的代码,这里有几点说明(特别是第二点):</span>
<span style="font-size:18px;">1.swap函数:两个数的异或满足交换律,代入验证即可</span>
<span style="font-size:18px;">2.cal函数中i=0,j=0开始的循环消项函数中为什么可以用异或运算代替正常的加减运算:</span>
<span style="font-size:18px;">假设矩阵a,b(由上到下,a<b)两行,map[a][j]==1,map[b][j]==1:为形成上三角矩阵,要用map[a][j]消去map[b][j],一般情况下,显然a行系数全部乘上-1,再与b行相加,消去map[b][j],但这会导致b行系数中出现-1项(假设-1对应方程中的-x2项)。</span>
<span style="font-size:18px;">此时可以将b行中的-1项转换为系数为1项。注意,矩阵每一行数对应的每一个方程的系数,而题中方程为模线性方程(mod 2),只要在b行代表的方程两边加上2*(x2),由余数定理知该操作不会影响最终解,也将矩阵中-1项转换为1项。</span>
<span style="font-size:18px;">类似的,也就是说每一次消项操作只会使矩阵中的数变为0或1,那么就会与异或联系在一起:</span>
<span style="font-size:18px;">(1)若map[a][k]==0,显然该项乘以-1,再加上map[b][k],是不会影响map[b][k]的,相当于0^map[b][k]=map[b][k];</span>
<span style="font-size:18px;">(2)若map[a][k]==1,该项乘以-1,若map[b][k]==1,则map[a][k]+map[b][k]==0,相当于1^map[b][k]=0;</span>
<span style="font-size:18px;">(3)若map[a][k]==1,该项乘以-1,若map[b][k]==0,则map[a][k]+map[b][k]==-1(该项系数可以转换为1),相当于1^map[b][k]=1.</span>
<span style="font-size:18px;">综合上述,消项结果就相当于map[a][k]^map[b][k]的结果</span>
<span style="font-size:18px;"></span><pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
short sta[35],end[35],map[35][35];
int n;
void swap(int &a,int &b){
a=a^b;
b=a^b;
a=a^b;
}
int cal(){
int i,j,k,l;
for(i=0,j=0;j<n;){//两种情况退出:最后行的倒数第二格为0或不为0
int id=i;
for(l=i+1;l<n;l++){
if(map[l][j]>map[id][j])
id=l;
}
if(map[id][j]==0){
j++;
continue;
}
if(id!=i){
for(l=j;l<=n;l++){
swap(map[id][l],map[i][l]);
}
}
for(l=i+1;l<n;l++){//消项
if(!map[l][j]) continue;
for(k=j;k<=n;k++){
map[l][k]=map[l][k]^map[i][k];//错将i写为id,WA
//原来相消会出现系数为-1的项,那么在等式两边加上该项系数为1时的两倍,方程解不变
}
}
i++;j++;
}
for(k=i;k<n;k++)
if(map[k][n])
return -1;
return 1<<(n-i);
}
int main(){
//freopen("D:\\INPUT.txt","r", stdin);
int k;
cin>>k;
while(k--){
scanf("%d",&n);
int i,j,l;
for(i=0;i<n;i++) scanf("%d",&sta[i]);
for(i=0;i<n;i++) scanf("%d",&end[i]);
memset(map,0,sizeof(map));
while(scanf("%d%d",&j,&l),j||l){
map[l-1][j-1]=1;
}
for(i=0;i<n;i++){
map[i][n]=sta[i]^end[i];
map[i][i]=1;
}
int ans=cal();
if(ans==-1){
cout<<"Oh,it's impossible~!!"<<endl;
}
else{
cout<<ans<<endl;
}
}
return 0;
}