高斯消元

 

开关问题

 POJ - 1830

题意:n个开关n个灯,每个开关负责多个灯,给出灯的初始状态和最终状态,问有多少种摁开关的方案(与顺序无关)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 const int maxn=35;
 6 int a[maxn][maxn],b[maxn];
 7 int n;
 8 void gauss_elimination(){
 9     for(int i=0,col=0;i<n-1&&col<=n;){
10         if(a[i][col]==0){
11             int r;
12             for(r=i+1;r<n;r++){
13                 if(a[r][col]){
14                     for(int j=col;j<=n;j++){
15                         swap(a[i][j],a[r][j]);
16                     }
17                     break;
18                 }
19             }
20             if(r==n){  //这列下面都为0
21                 col++;
22                 continue;
23             }
24         }
25         //消元
26         for(int r=i+1;r<n;r++){
27             if(a[r][col]){
28                 for(int j=col;j<=n;j++){
29                     a[r][j]^=a[i][j];
30                 }
31             }
32         }
33         i++;col++;
34     }
35 }
36 int solve(){
37     for(int i=0;i<n;i++){
38         int flag=1;
39         for(int j=0;j<n;j++){
40             if(a[i][j]) {
41                 flag=0;
42                 break;
43             }
44         }
45         if(flag){
46             for(int r=i;r<n;r++){
47                 if(a[r][n]){
48                     return -1;
49                 }
50             }
51             return 1<<(n-i);
52         }
53     }
54     return 1;
55 }
56 int main(){
57     int t;
58     scanf("%d",&t);
59     while(t--){
60         memset(a,0,sizeof(a));
61         scanf("%d",&n);
62         for(int i=0;i<n;i++){
63             scanf("%d",&b[i]);
64         }
65         int e;
66         for(int i=0;i<n;i++){
67             scanf("%d",&e);
68             b[i]^=e;   //1为需要变化
69         }
70         int u,v;
71         while(scanf("%d%d",&u,&v)&&(u||v)){
72             a[v-1][u-1]=1;
73         }
74         for(int i=0;i<n;i++){
75             a[i][i]=1;
76             a[i][n]=b[i];
77         }
78         gauss_elimination();
79         int ans=solve();
80         if(ans<0){
81             puts("Oh,it's impossible~!!");
82         }else {
83             printf("%d\n",ans);
84         }
85     }
86     return 0;
87 }
有点拉杂
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 const int maxn=35;
 7 int a[maxn][maxn],b[maxn];
 8 int n;
 9 int gauss_elimination(){
10     int i=0,j=0;
11     while(j<n){ //列主元?
12         int r=i;
13         for(int k=i+1;k<n;k++)
14             if(fabs(a[k][j])>fabs(a[r][j])) r=k;
15         if(r!=i) for(int k=j;k<=n;k++) swap(a[r][k],a[i][k]);
16         if(a[i][j]==0){ j++; continue;}  //
17         for(int k=i+1;k<n;k++){     //消元
18             if(a[k][j]==0) continue;
19             for(int col=j;col<=n;col++) a[k][col]^=a[i][col];
20         }
21         i++;j++;
22     }
23     for(int k=i;k<n;k++){
24         if(a[k][n]!=0) return -1;
25     }
26     return 1<<(n-i);
27 }
28 
29 int main(){
30     int t;
31     scanf("%d",&t);
32     while(t--){
33         memset(a,0,sizeof(a));
34         scanf("%d",&n);
35         for(int i=0;i<n;i++) scanf("%d",&b[i]);
36         int e;
37         for(int i=0;i<n;i++){
38             scanf("%d",&e);
39             b[i]^=e;   //1为需要变化
40         }
41         int u,v;
42         while(scanf("%d%d",&u,&v)&&(u||v)) a[v-1][u-1]=1;
43         
44         for(int i=0;i<n;i++){
45             a[i][i]=1;
46             a[i][n]=b[i];
47         }
48         int ans=gauss_elimination();
49         if(ans<0) puts("Oh,it's impossible~!!");
50         else printf("%d\n",ans);
51     }
52     return 0;
53 }

 

Lanterns

 HDU - 3364 

题意:和上一题基本一样,查询多次。

用的更普遍的方法~

模线性方程组高斯消元模板

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int mod=2;
 4 const int maxn=55;
 5 int a[maxn][maxn],b[maxn][maxn];
 6 int x[maxn];
 7 int n,m;
 8 
 9 int gcd(int a,int b){
10     return b==0?a:gcd(b,a%b);
11 }
12 int lcm(int a,int b){
13     int g=gcd(a,b);
14     return a/g*b;
15 }
16 void exgcd(int a,int b,int &d,int &x,int &y){
17     if(!b){d=a;x=1;y=0;}
18     else {exgcd(b,a%b,d,y,x); y-=x*(a/b);}
19 }
20 
21 int gauss(int n,int m){
22     int r,c;
23     for(r=0,c=0;r<n&&c<m;c++){
24         int max_r=r;
25         for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i;
26         if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]);
27         if(!a[r][c]) continue;
28         for(int i=r+1;i<n;i++) if(a[i][c]){
29             int d=lcm(a[i][c],a[r][c]);
30             int t1=d/a[i][c],t2=d/a[r][c];
31             for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod;
32         }
33         r++;
34     }
35     for(int i=r;i<n;i++) if(a[i][m]) return -1;
36     /*
37     for(int i=r-1;i>=0;i--){
38         x[i]=a[i][m];
39         for(int j=i+1;j<m;j++){
40             x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod;
41         }
42         int x1,y1,d;
43         exgcd(a[i][i],mod,d,x1,y1);
44         x1=((x1%mod)+mod)%mod;
45         x[i]=x[i]*x1%mod;
46     }
47     */
48     return m-r;
49 }
50 
51 int main(){
52     int t,kase=0;
53     scanf("%d",&t);
54     while(t--){
55         printf("Case %d:\n",++kase);
56         memset(a,0,sizeof(a));
57         memset(b,0,sizeof(b));
58         scanf("%d%d",&n,&m);
59         int k;
60         for(int i=0;i<m;i++){
61             scanf("%d",&k);
62             int u;
63             while(k--){
64                 scanf("%d",&u);
65                 b[u-1][i]=1;
66             }
67         }
68         int q;
69         scanf("%d",&q);
70         while(q--){
71             for(int i=0;i<n;i++) scanf("%d",&a[i][m]);
72             for(int i=0;i<n;i++){
73                 for(int j=0;j<m;j++)
74                     a[i][j]=b[i][j];
75             }
76             int ans=gauss(n,m);
77             if(ans==-1) puts("0");
78             else printf("%lld\n",(1ll<<ans));
79         }
80     }
81     return 0;
82 }
View Code

 gcd写错了竟然过了,,结果下一道题坑了好久=_=||

 

EXTENDED LIGHTS OUT

 POJ - 1222 

题意:还是开关~

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn=33;
 7 int a[maxn][maxn];
 8 int x[maxn];
 9 
10 void init(int n,int m){
11     for(int i=0;i<n;i++){
12         for(int j=0;j<m;j++){
13             int num=i*m+j;
14             a[num][num]=1;
15             if(i!=0) a[num-m][num]=1;
16             if(i!=n-1) a[num+m][num]=1;
17             if(j!=0) a[num-1][num]=1;
18             if(j!=m-1) a[num+1][num]=1;
19         }
20     }
21 }
22 void gauss(int n,int m){
23     int r,c;
24     for(r=0,c=0;r<n&&c<m;c++){
25         int max_r=r;
26         for(int i=r+1;i<n;i++) if(a[i][c]>a[max_r][c]) max_r=i;
27         if(max_r!=r) for(int j=c;j<=m;j++) swap(a[max_r][j],a[r][j]);
28         if(a[r][r]==0) continue;
29         for(int i=r+1;i<n;i++){
30             if(a[i][c]==0) continue;  //!!!
31             for(int j=c;j<=m;j++) a[i][j]^=a[r][j];
32         }
33         r++;
34     }
35     //题目说了有唯一解
36     for(int i=n-1;i>=0;i--){
37         x[i]=a[i][30];
38         for(int j=i+1;j<m;j++) if(a[i][j]) x[i]^=x[j];
39     }
40     return;
41 }
42 int main(){
43     int t;
44     int kase=0;
45     scanf("%d",&t);
46     while(t--){
47         printf("PUZZLE #%d\n",++kase);
48         memset(a,0,sizeof(a));
49         for(int i=0;i<30;i++) scanf("%d",&a[i][30]);
50         init(5,6);
51         gauss(30,30);
52         int id=0;
53         for(int i=0;i<5;i++){
54             for(int j=0;j<6;j++) {
55                 printf("%d%c",x[id++],j==5?'\n':' ');
56             }
57         }
58     }
59     return 0;
60 }
View Code

 

 

Painter's Problem

 POJ - 1681 

题意:开关=_=||

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int inf=0x3f3f3f3f;
 7 const int maxn=16;
 8 int a[maxn*maxn][maxn*maxn];
 9 int x[maxn],fx[maxn];
10 
11 int gauss(int n,int m){
12     int r,c;
13     int num=0;
14     for(r=0,c=0;r<n&&c<m;c++){
15         int max_r=r;
16         for(int i=r+1;i<n;i++) if(a[i][c]>a[r][c]) max_r=i;
17         if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]);
18         if(a[r][r]==0) {fx[num++]=c;continue;}
19         for(int i=r+1;i<n;i++){
20             if(a[i][c]==0) continue;
21             for(int j=c;j<=m;j++) a[i][j]^=a[r][j];
22         }
23         r++;
24     }
25     for(int i=r;i<n;i++) if(a[i][m]) return -1;
26     int sta=1<<(m-r);
27     int res=inf;
28     for(int i=0;i<sta;i++){
29         int cnt=0;
30         int id=i;
31         for(int j=0;j<num;j++){
32             x[fx[j]]=(id&1);
33             if(x[fx[j]]) cnt++;
34             id>>=1;
35         }
36         for(int j=r-1;j>=0;j--){
37             x[j]=a[j][m];
38             for(int k=j+1;k<m;k++) if(a[j][k]) x[j]^=x[k];
39             if(x[j]) cnt++;
40         }
41         if(cnt<res) res=cnt;
42     }
43     return res;
44 }
45 void init(int n){
46     for(int i=0;i<n;i++){
47         for(int j=0;j<n;j++){
48             int num=i*n+j;
49             a[num][num]=1;
50             if(i!=0) a[num-n][num]=1;
51             if(i!=n-1) a[num+n][num]=1;
52             if(j!=0) a[num-1][num]=1;
53             if(j!=n-1) a[num+1][num]=1;
54         }
55     }
56 }
57 int main(){
58     int t;
59     scanf("%d",&t);
60     while(t--){
61         memset(a,0,sizeof(a));
62         int n;
63         scanf("%d",&n);
64         int m=n*n;
65         for(int i=0;i<m;i++){
66             char c=getchar();
67             while(c!='y'&&c!='w') c=getchar();
68             a[i][m]=c=='w'?1:0;
69         }
70         init(n);
71         int ans=gauss(m,m);
72         if(ans==-1) puts("inf");
73         else printf("%d\n",ans);
74     }
75 }
View Code

 

SETI

 POJ - 2065

题意:

模线性方程组高斯消元模板

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn=75;
 7 int a[maxn][maxn];
 8 int x[maxn];
 9 char s[75];
10 int mod;
11 
12 int gcd(int a,int b){
13     return b==0?a:gcd(b,a%b);
14 }
15 int lcm(int a,int b){
16     return a/gcd(a,b)*b;
17 }
18 void exgcd(int a,int b,int &d,int &x,int &y){
19     if(!b){d=a;x=1;y=0;}
20     else {exgcd(b,a%b,d,y,x); y-=x*(a/b);}
21 }
22 
23 int gauss(int n,int m){
24     int r,c;
25     for(r=0,c=0;r<n&&c<m;c++){
26         int max_r=r;
27         for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i;
28         if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]);
29         if(!a[r][c]) continue;
30         for(int i=r+1;i<n;i++) if(a[i][c]){
31             int d=lcm(abs(a[i][c]),abs(a[r][c]));
32             int t1=d/a[i][c],t2=d/a[r][c];
33             for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod;
34         }
35         r++;
36     }
37     for(int i=r;i<n;i++) if(a[i][m]) return -1; //无解
38     for(int i=r-1;i>=0;i--){
39         x[i]=a[i][m];
40         for(int j=i+1;j<m;j++){
41             x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod;
42         }
43         int x1,y1,d;
44         exgcd(a[i][i],mod,d,x1,y1);
45         x1=((x1%mod)+mod)%mod;
46         x[i]=x[i]*x1%mod;
47     }
48     if(r<m) return m-r;  //自由变元
49     return 1;//唯一解
50 }
51 int quickpow(int a,int b,int mod){
52     int ans=1,temp=a%mod;
53     while(b){
54         if(b&1) ans=(ans*temp)%mod;
55         b>>=1;
56         temp=temp*temp%mod;
57     }
58     return ans;
59 }
60 int main(){
61    int t;
62    scanf("%d",&t);
63    while(t--){
64         int n,m;
65         memset(a,0,sizeof(a));
66         memset(x,0,sizeof(x));
67         scanf("%d%s",&mod,s);
68         n=m=strlen(s);
69         for(int i=0;i<n;i++){
70             a[i][m]=s[i]=='*'?0:s[i]-'a'+1;
71             for(int j=0;j<n;j++)
72                 a[i][j]=quickpow(i+1,j,mod);
73         }
74         int ans=gauss(n,m);
75         for(int i=0;i<n-1;i++) printf("%d ",x[i]);
76         printf("%d\n",x[n-1]);
77    }
78    return 0;
79 }
View Code

 

 

Kind of a Blur

 HDU - 3359

题意:让求矩阵x。给出n×m的矩阵b,b[i][j]为到这个位置的曼哈顿距离不大于d的x[i][j]的和除以个数。

浮点数高斯消元模板题。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double eps=1e-12;
 4 const int maxn=22;
 5 int n,m;
 6 int tot;
 7 int d;
 8 double a[maxn*maxn][maxn*maxn];
 9 double b[maxn][maxn];
10 double x[maxn*maxn];
11 
12 int count_(int x,int y){
13     int ans=0;
14     for(int i=0;i<n;i++)
15         for(int j=0;j<m;j++)
16             if(abs(i-x)+abs(y-j)<=d) ans++;
17     return ans;
18 }
19 
20 void init(){
21     int num=0;
22     for(int i=0;i<n;i++){
23         for(int j=0;j<m;j++){
24             int cnt=count_(i,j);
25             for(int k=0;k<n;k++)
26             for(int g=0;g<m;g++){
27                 if(abs(k-i)+abs(g-j)<=d)
28                     a[num][k*m+g]=1.0/cnt;
29             }
30             a[num++][tot]=b[i][j];
31         }
32     }
33 }
34 void gauss(){
35     for(int r=0;r<tot;r++){
36         int max_r=r;
37         for(int i=r+1;i<tot;i++)
38             if(fabs(a[i][r])>fabs(a[max_r][r])) max_r=i;
39         if(max_r!=r){
40             for(int j=0;j<=tot;j++) swap(a[r][j],a[max_r][j]);
41         }
42         if(fabs(a[r][r])<eps) continue;
43         //消元
44         for(int i=r+1;i<tot;i++){
45             double ta=a[i][r]/a[r][r];
46             for(int j=r;j<=tot;j++) a[i][j]-=ta*a[r][j];
47         }
48         /*
49         精度更高
50         for(int j=tot;j>=r;j--){
51             for(int i=r+1;i<tot;i++) a[i][j]-=a[i][r]/a[r][r]*a[r][j];
52         }
53         */
54     }
55     //回代
56     for(int i=tot-1;i>=0;i--){
57         double temp=a[i][tot];
58         for(int j=i+1;j<tot;j++)
59             temp-=a[i][j]*x[j];
60         x[i]=temp/a[i][i];
61     }
62 }
63 int main(){
64     int kase=0;
65     while(scanf("%d%d%d",&m,&n,&d)!=EOF&&(n+m+d)){
66         memset(a,0,sizeof(a));
67         tot=n*m;
68         if(kase++) puts("");
69         for(int i=0;i<n;i++)
70             for(int j=0;j<m;j++)
71                 scanf("%lf",&b[i][j]);
72         init();
73         gauss();
74         int id=0;
75         for(int i=0;i<n;i++){
76             for(int j=0;j<m;j++) printf("%8.2lf",x[id++]);
77             puts("");
78         }
79     }
80     return 0;
81 }
View Code

 

 

The Water Bowls

 POJ - 3185 

题意:还是开关问题~每个开关可以影响自己和相邻的灯。

枚举自由变元

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 const int inf=0x3f3f3f3f;
 7 //const int mod=2;
 8 const int maxn=25;
 9 int a[maxn][maxn];
10 int x[maxn],free_x[maxn];
11 int n,m;
12 /*
13 int gcd(int a,int b){
14     return b==0?a:gcd(b,a%b);
15 }
16 int lcm(int a,int b){
17     return a/gcd(a,b)*b;
18 }
19 void exgcd(int a,int b,int &d,int &x,int &y){
20     if(!b){d=a;x=1;y=0;}
21     else {exgcd(b,a%b,d,y,x); y-=x*(a/b);}
22 }
23 */
24 
25 int gauss(int n,int m){
26     int r,c;
27     int num=0;
28     for(r=0,c=0;r<n&&c<m;c++){
29         int max_r=r;
30         for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i;
31         if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]);
32         if(!a[r][c]) {free_x[num++]=c;continue;}  //
33         for(int i=r+1;i<n;i++) if(a[i][c]){
34             /*
35              int d=lcm(abs(a[i][c]),abs(a[r][c]));
36             int t1=d/a[i][c],t2=d/a[r][c];
37             for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod;
38             */
39             for(int j=c;j<=m;j++) a[i][j]^=a[r][j];
40         }
41         r++;
42     }
43     for(int i=r;i<n;i++) if(a[i][m]) return -1;
44     /*
45     for(int i=r-1;i>=0;i--){
46         x[i]=a[i][m];
47         for(int j=i+1;j<m;j++){
48             x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod;
49         }
50         int x1,y1,d;
51         exgcd(a[i][i],mod,d,x1,y1);
52         x1=((x1%mod)+mod)%mod;
53         x[i]=x[i]*x1%mod;
54     }
55     */
56     int sta=1<<(m-r);
57     int res=inf;
58     //枚举自由变元
59     for(int i=0;i<sta;i++){
60         int cnt=0;
61         int id=i;
62         for(int j=0;j<m-r;j++){
63             x[free_x[j]]=(id&1);
64             if(x[free_x[j]]) cnt++;
65             id>>=1;
66         }
67         for(int j=r-1;j>=0;j--){
68             int temp=a[j][m];
69             for(int k=j+i;k<m;k++){
70                 if(a[j][k]) temp^=x[k];
71             }
72             x[j]=temp;
73             if(x[j]) cnt++;
74         }
75         if(cnt<res) res=cnt;
76     }
77     return res;
78 }
79 void init(int n,int m){
80     for(int i=0;i<n;i++){
81         for(int j=0;j<m;j++) a[i][j]=0;
82         a[i][i]=1;
83         if(i>0) a[i][i-1]=1;
84         if(i<19) a[i][i+1]=1;
85     }
86 }
87 int main(){
88     init(20,20);
89     memset(free_x,0,sizeof(free_x));
90     for(int i=0;i<20;i++){
91         scanf("%d",&a[i][20]);
92     }
93     int ans=gauss(20,20);
94     printf("%d\n",ans);
95     return 0;
96 }
View Code

 

posted @ 2017-08-13 15:50  yijiull  阅读(151)  评论(0编辑  收藏  举报