高斯消元解異或方程組-開關問題
阿新 • • 發佈:2019-02-11
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<iomanip> #include<vector> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int maxn=40; const int inf=0x3f3f3f3f; int a[maxn][maxn];//增廣矩陣 int x[maxn];//解集; int free_x[maxn];//用來儲存自由變元(多解列舉自由變元使用) int free_num;//不確定變元的個數 //有equ個方程,var個變元。增廣矩陣行數為equ, //分別為0-equ-1,列數為var+1,分別為0到var int equ,var; int gauss() { int i,j,k; int col;//當前處理的列 int max_r;//當前這列絕對值最大的行 free_num=0; //化為上三角 for(k=0,col=0;k<equ&&col<var;k++,col++) { max_r=k; for(i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) max_r=i; } if(a[max_r][col]==0) {//絕對值最大是0,說明該col列k行一下全為零,則處理該行的下一列 k--; free_x[free_num++]=col;//這個是自由變元 continue; } if(max_r!=k) { for(i=col;i<=var;i++) swap(a[k][i],a[max_r][i]); } //找到該col列(當前處理的列)絕對值最大的那行與第k行交換(為了在除法時減少誤差) for(i=k+1;i<equ;i++)//列舉要消去的行 { if(a[i][col]) { for(j=col;j<=var;j++) a[i][j]^=a[k][j]; } } } // //此時k的值表示的是係數矩陣的值都為0的那些行的第一行 for(i=k;i<equ;i++) { if(a[i][col]) return -1;//無解 } if(var>k)//無窮解 return var-k;//自由變元個數 for(i=var-1;i>=0;i--)//唯一解 { x[i]=a[i][var]; for(j=i+1;j<var;j++) x[i]^=(a[i][j]&&x[j]); } return 0; } void dfs(int x,int y) { int t=x*6+y; int dx[2]={1,-1}; int dy[2]={1,-1}; a[t][t]=1;//對自己的影響! for(int i=0;i<2;i++) { if(y+dx[i]>=0&&y+dx[i]<=5) { int tt=x*6+y+dx[i]; a[tt][t]=1; } } for(int i=0;i<=2;i++) { if(x+dy[i]>=0&&x+dy[i]<=4) { int tt=(x+dy[i])*6+y; a[tt][t]=1; } } } int main() { int n,i,j,ca,l,d,res; ca=0; scanf("%d",&n); while(n--) { memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); l=0; for(i=0;i<5;i++) { for(j=0;j<6;j++) { scanf("%d",&d); a[l++][30]=d;//構造增廣矩陣 } } for(i=0;i<5;i++) { for(j=0;j<6;j++) dfs(i,j);//構造曾廣矩陣,按列賦值 } equ=var=30; res=gauss(); printf("PUZZLE #%d\n",++ca); for(i=0;i<30;i++) { printf("%d",x[i]); if((i+1)%6==0) printf("\n"); else printf(" "); } } }
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<iomanip> #include<vector> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int maxn=16*16; const int inf=0x3f3f3f3f; int a[maxn][maxn];//增廣矩陣 int x[maxn];//解集; int free_x[maxn];//用來儲存自由變元(多解列舉自由變元使用) int free_num;//不確定變元的個數 //有equ個方程,var個變元。增廣矩陣行數為equ, //分別為0-equ-1,列數為var+1,分別為0到var int equ,var; int gauss() { int i,j,k; int col;//當前處理的列 int max_r;//當前這列絕對值最大的行 free_num=0; //化為上三角 for(k=0,col=0;k<equ&&col<var;k++,col++) { max_r=k; for(i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) max_r=i; } if(a[max_r][col]==0) {//絕對值最大是0,說明該col列k行一下全為零,則處理該行的下一列 k--; free_x[free_num++]=col;//這個是自由變元 continue; } if(max_r!=k) { for(i=col;i<=var;i++) swap(a[k][i],a[max_r][i]); } //找到該col列(當前處理的列)絕對值最大的那行與第k行交換(為了在除法時減少誤差) for(i=k+1;i<equ;i++)//列舉要消去的行 { if(a[i][col]) { for(j=col;j<=var;j++) a[i][j]^=a[k][j]; } } } // //此時k的值表示的是係數矩陣的值都為0的那些行的第一行 for(i=k;i<equ;i++) { if(a[i][col]) return -1;//無解 } if(var>k)//無窮解 return var-k;//自由變元個數 for(i=var-1;i>=0;i--)//唯一解 { x[i]=a[i][var]; for(j=i+1;j<var;j++) x[i]^=(a[i][j]&&x[j]); } return 0; } void dfs(int x,int y,int n) { int t=x*n+y; int dx[2]={1,-1}; int dy[2]={1,-1}; a[t][t]=1;//對自己的影響! for(int i=0;i<2;i++) { if(y+dx[i]>=0&&y+dx[i]<=n-1) { int tt=x*n+y+dx[i]; a[tt][t]=1; } } for(int i=0;i<=2;i++) { if(x+dy[i]>=0&&x+dy[i]<=n-1) { int tt=(x+dy[i])*n+y; a[tt][t]=1; } } } int solve() { int t=gauss(); if(t==-1) return -1;//無解 else if(t==0)//唯一解 { int ans=0; for(int i=0;i<equ;i++) ans+=x[i];//按幾下,即x[i]有幾個1 return ans; } else//無窮解,列舉自由變元,找出最小的步數 { int ans=inf; int tot=(1<<t);//t=var-k; for(int i=0;i<tot;i++) { int cnt=0; for(int j=0;j<t;j++) { if(i&(1<<j)) { x[free_x[j]]=1; cnt++; } else x[free_x[j]]=0; } for(int j=var-t-1;j>=0;j--) { int idx; for(idx=j;idx<var;idx++) if(a[j][idx]) break; x[idx]=a[j][var]; for(int l=idx+1;l<var;l++) if(a[j][l]) x[idx]^=x[l]; cnt+=x[idx]; } ans=min(ans,cnt); } return ans; } } int main() { int t,n,i,j,l,res; string s; scanf("%d",&t); while(t--) { scanf("%d",&n); equ=var=n*n; memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); l=0; for(i=0;i<n;i++) { cin>>s; for(j=0;j<n;j++) { if(s[j]=='y') a[l++][n*n]=0; else a[l++][n*n]=1; } } for(i=0;i<n;i++) { for(j=0;j<n;j++) { dfs(i,j,n); } } res=solve(); if(res==-1) printf("inf\n"); else printf("%d\n",res); } }
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<iomanip> #include<vector> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int maxn=16*16; const int inf=0x3f3f3f3f; int a[maxn][maxn];//增廣矩陣 int x[maxn];//解集; int free_x[maxn];//用來儲存自由變元(多解列舉自由變元使用) int free_num;//不確定變元的個數 //有equ個方程,var個變元。增廣矩陣行數為equ, //分別為0-equ-1,列數為var+1,分別為0到var int equ,var; int gauss() { int i,j,k; int col;//當前處理的列 int max_r;//當前這列絕對值最大的行 free_num=0; //化為上三角 for(k=0,col=0;k<equ&&col<var;k++,col++) { max_r=k; for(i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) max_r=i; } if(a[max_r][col]==0) {//絕對值最大是0,說明該col列k行一下全為零,則處理該行的下一列 k--; free_x[free_num++]=col;//這個是自由變元 continue; } if(max_r!=k) { for(i=col;i<=var;i++) swap(a[k][i],a[max_r][i]); } //找到該col列(當前處理的列)絕對值最大的那行與第k行交換(為了在除法時減少誤差) for(i=k+1;i<equ;i++)//列舉要消去的行 { if(a[i][col]) { for(j=col;j<=var;j++) a[i][j]^=a[k][j]; } } } // //此時k的值表示的是係數矩陣的值都為0的那些行的第一行 for(i=k;i<equ;i++) { if(a[i][col]) return -1;//無解 } if(var>k)//無窮解 return var-k;//自由變元個數 for(i=var-1;i>=0;i--)//唯一解 { x[i]=a[i][var]; for(j=i+1;j<var;j++) x[i]^=(a[i][j]&&x[j]); } return 0; } void dfs(int x,int y) { int t=x*4+y; int dx[2]={1,-1}; int dy[2]={1,-1}; a[t][t]=1; for(int i=0;i<2;i++) { if(y+dx[i]>=0&&y+dx[i]<=3) { int tt=x*4+y+dx[i]; a[tt][t]=1; } } for(int i=0;i<2;i++) { if(x+dy[i]>=0&&x+dy[i]<=3) { int tt=(x+dy[i])*4+y; a[tt][t]=1; } } } int solve() { int t=gauss(); if(t==-1) return -1;//無解 else if(t==0)//唯一解 { int ans=0; for(int i=0;i<equ;i++) ans+=x[i];//按幾下,即x[i]有幾個1 return ans; } else//無窮解,列舉自由變元,找出最小的步數 { int ans=inf; int tot=(1<<t);//t=var-k; for(int i=0;i<tot;i++) { int cnt=0; for(int j=0;j<t;j++) { if(i&(1<<j)) { x[free_x[j]]=1; cnt++; } else x[free_x[j]]=0; } for(int j=var-t-1;j>=0;j--) { int idx; for(idx=j;idx<var;idx++) if(a[j][idx]) break; x[idx]=a[j][var]; for(int l=idx+1;l<var;l++) if(a[j][l]) x[idx]^=x[l]; cnt+=x[idx]; } ans=min(ans,cnt); } return ans; } } int main() { int i,j,res1,res2,l; string s,ss[10]; l=0; memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); for(i=0;i<4;i++) { cin>>s; ss[i]=s; for(j=0;j<4;j++) { if(s[j]=='b') a[l++][16]=1; else //l++; a[l++][16]=0; } }//cout<<l<<endl; for(i=0;i<4;i++) { for(j=0;j<4;j++) dfs(i,j); } equ=var=16; res1=solve(); memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); l=0; for(i=0;i<4;i++) { //cout<<ss[i]<<endl; for(j=0;j<4;j++) { if(ss[i][j]=='w') a[l++][16]=1; else //l++; a[l++][16]=0; } }//cout<<l<<endl; for(i=0;i<4;i++) { for(j=0;j<4;j++) dfs(i,j); } res2=solve(); //cout<<res1<<" "<<res2<<endl; if(res1==-1&&res2==-1) printf("Impossible\n"); else if(res1==-1) printf("%d\n",res2); else if(res2==-1) printf("%d\n",res1); else printf("%d\n",min(res1,res2)); }
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=16*16;
const int inf=0x3f3f3f3f;
int a[maxn][maxn];//增廣矩陣
int x[maxn];//解集;
int free_x[maxn];//用來儲存自由變元(多解列舉自由變元使用)
int free_num;//不確定變元的個數
//有equ個方程,var個變元。增廣矩陣行數為equ,
//分別為0-equ-1,列數為var+1,分別為0到var
int equ,var;
int gauss()
{
int i,j,k;
int col;//當前處理的列
int max_r;//當前這列絕對值最大的行
free_num=0;
//化為上三角
for(k=0,col=0;k<equ&&col<var;k++,col++)
{
max_r=k;
for(i=k+1;i<equ;i++)
{
if(abs(a[i][col])>abs(a[max_r][col]))
max_r=i;
}
if(a[max_r][col]==0)
{//絕對值最大是0,說明該col列k行一下全為零,則處理該行的下一列
k--;
free_x[free_num++]=col;//這個是自由變元
continue;
}
if(max_r!=k)
{
for(i=col;i<=var;i++)
swap(a[k][i],a[max_r][i]);
}
//找到該col列(當前處理的列)絕對值最大的那行與第k行交換(為了在除法時減少誤差)
for(i=k+1;i<equ;i++)//列舉要消去的行
{
if(a[i][col])
{
for(j=col;j<=var;j++)
a[i][j]^=a[k][j];
}
}
}
// //此時k的值表示的是係數矩陣的值都為0的那些行的第一行
for(i=k;i<equ;i++)
{
if(a[i][col])
return -1;//無解
}
if(var>k)//無窮解
return var-k;//自由變元個數
for(i=var-1;i>=0;i--)//唯一解
{
x[i]=a[i][var];
for(j=i+1;j<var;j++)
x[i]^=(a[i][j]&&x[j]);
}
return 0;
}
void dfs(int x,int y)
{
int t=x*20+y;
int dx[2]={1,-1};
a[t][t]=1;
for(int i=0;i<2;i++)
{
if(y+dx[i]>=0&&y+dx[i]<=19)
{
int tt=x*20+y+dx[i];
a[tt][t]=1;
}
}
}
int solve()
{
int t=gauss();
if(t==-1)
return -1;//無解
else if(t==0)//唯一解
{
int ans=0;
for(int i=0;i<equ;i++)
ans+=x[i];//按幾下,即x[i]有幾個1
return ans;
}
else//無窮解,列舉自由變元,找出最小的步數
{
int ans=inf;
int tot=(1<<t);//t=var-k;
for(int i=0;i<tot;i++)
{
int cnt=0;
for(int j=0;j<t;j++)
{
if(i&(1<<j))
{
x[free_x[j]]=1;
cnt++;
}
else
x[free_x[j]]=0;
}
for(int j=var-t-1;j>=0;j--)
{
int idx;
for(idx=j;idx<var;idx++)
if(a[j][idx])
break;
x[idx]=a[j][var];
for(int l=idx+1;l<var;l++)
if(a[j][l])
x[idx]^=x[l];
cnt+=x[idx];
}
ans=min(ans,cnt);
}
return ans;
}
}
int main()
{
int i,j,d,l,res;
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));
l=0;
for(i=0;i<20;i++)
{
scanf("%d",&d);
a[l++][20]=d;
}
for(i=0;i<1;i++)
{
for(j=0;j<20;j++)
{
dfs(i,j);
}
}
equ=var=20;
res=solve();
printf("%d\n",res);
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=16*16;
const int inf=0x3f3f3f3f;
int a[maxn][maxn];//增廣矩陣
int x[maxn];//解集;
int free_x[maxn];//用來儲存自由變元(多解列舉自由變元使用)
int free_num;//不確定變元的個數
//有equ個方程,var個變元。增廣矩陣行數為equ,
//分別為0-equ-1,列數為var+1,分別為0到var
int equ,var;
int gauss()
{
int i,j,k;
int col;//當前處理的列
int max_r;//當前這列絕對值最大的行
free_num=0;
//化為上三角
for(k=0,col=0;k<equ&&col<var;k++,col++)
{
max_r=k;
for(i=k+1;i<equ;i++)
{
if(abs(a[i][col])>abs(a[max_r][col]))
max_r=i;
}
if(a[max_r][col]==0)
{//絕對值最大是0,說明該col列k行一下全為零,則處理該行的下一列
k--;
free_x[free_num++]=col;//這個是自由變元
continue;
}
if(max_r!=k)
{
for(i=col;i<=var;i++)
swap(a[k][i],a[max_r][i]);
}
//找到該col列(當前處理的列)絕對值最大的那行與第k行交換(為了在除法時減少誤差)
for(i=k+1;i<equ;i++)//列舉要消去的行
{
if(a[i][col])
{
for(j=col;j<=var;j++)
a[i][j]^=a[k][j];
}
}
}
// //此時k的值表示的是係數矩陣的值都為0的那些行的第一行
for(i=k;i<equ;i++)
{
if(a[i][col])
return -1;//無解
}
return 1<<(var-k);
}
void dfs(int x,int y)
{
int t=x*20+y;
int dx[2]={1,-1};
a[t][t]=1;
for(int i=0;i<2;i++)
{
if(y+dx[i]>=0&&y+dx[i]<=19)
{
int tt=x*20+y+dx[i];
a[tt][t]=1;
}
}
}
int main()
{
int k,n,aaa,bbb,i,c[maxn],d[maxn],l,j,res;
scanf("%d",&k);
while(k--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&c[i]);
for(i=0;i<n;i++)
scanf("%d",&d[i]);
l=0;
memset(a,0,sizeof(a));
for(i=0;i<n;i++)
{
a[l++][n]=c[i]^d[i];
}
for(i=0;i<n;i++)
a[i][i]=1;
while(scanf("%d%d",&aaa,&bbb))
{
if(aaa==0&&bbb==0)
break;
aaa-=1;
bbb-=1;
a[bbb][aaa]=1;
}
equ=var=n;
res=gauss();
if(res==-1)
printf("Oh,it's impossible~!!\n");
else
printf("%d\n",res);
}
}