zoukankan      html  css  js  c++  java
  • 高斯消元

    开关问题

     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
    ",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
    ",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:
    ",++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
    ",(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
    ",++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?'
    ':' ');
    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
    ",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
    ",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
    ",ans);
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    Linux Bash
    grep 及正则表达式
    Linux 文件系统
    Linux 操作系统基础
    常见的磁盘I/O和网络I/O优化技巧
    NIO的工作方式
    网络I/O 工作机制
    spring Boot环境下dubbo+zookeeper的一个基础讲解与示例
    深入分析Java I/O 工作机制
    CDN工作机制和负载均衡
  • 原文地址:https://www.cnblogs.com/yijiull/p/7353718.html
Copyright © 2011-2022 走看看