高斯消元法(理论+习题)
高斯消元主要用来解多元一次线性方程组,主要用到的线性代数的知识详见矩阵行列式那一篇 (http://blog.csdn.net/zhoufenqin/article/details/7779707)
求解线性方程的结果会出现三种情况:无解,多解和唯一解。看下图
当某一行出现(0,0,……0,a) 时,方程无解。因为x1*0+x2*0+……+xn*0=a(a不为0)等式无解
当从某一行开始至最后一行,出现(0,0,……0)说明方程存在自由元,则会出现多解
当矩阵的秩等于等式个数时,有唯一解
红色格子最后的颜色由周围四个黄色格子变化次数决定,我们假设四个黄色格子的变化次数分别为X1,X2,X3,X4,则红色格子变化=(X1+X2+X3+X4)%2;
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
char str[20];
int paint[400][400];
int N,st;
int Find[10]={1,0,-1,0,0,-1,0,1};
void Guass()//高斯消元
{
int i,j,row,col;
for(row=0,col=0;row<st && col<st;row++,col++)//从第一行开始,不停地把原矩阵化成上三角
{
for(i=row;i<st;i++)//找到当前行以下的不为0的一行,有些也写成找当前行以下当前列值最大的一行,无影响
if(paint[i][col]) break;//找到就跳出
if(i==st)//如果下面每一行的当前列已经都是0,那么从当前行的后一个数继续找(回顾线性代数的知识)
{
row--;
continue;
}
if(i!=row)//如果找到的那一行不是当前行,则进行整行交换
{
for(j=0;j<st+1;j++) swap(paint[row][j],paint[i][j]);
}
for(i=row+1;i<st;i++)
if(paint[i][col])
{
for(j=col;j<st+1;j++)//把当前行一下的当前列的值化为0
paint[i][j]^=paint[row][j];
}
}
for(i=row;i<st;i++)//查找,如果出现(0,0,……0,a)方程无解
if(paint[i][st]!=0)
{
printf("inf\n");
return ;
}
int maxn=0x7fffffff;
int Num=1<<(st-row);//自由元有st-row个,则进行枚举
int pos;
int cnt;
for(i=0;i<Num;i++)//枚举的过程
{
cnt=0;
for(j=st-1,pos=i;j>=row;j--,pos>>=1)
{
paint[j][j]=pos&1;
if(paint[j][j]) cnt++;
}
for(j=row-1;j>=0;j--)
{
int temp=0;
for(int k=st-1;k>j;k--)
{
if(paint[j][k]==0) continue;
temp^=paint[k][k];
}
paint[j][j]=paint[j][st]^temp;
if(paint[j][j]) cnt++;
}
maxn=min(maxn,cnt);
}
printf("%d\n",maxn);
}
int L(int x,int y)
{
return x*N+y;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(paint,0,sizeof(paint));
scanf("%d",&N);
st=N*N;
for(int i=0;i<N;i++)
{
scanf("%s",str);
for(int j=0;j<N;j++)//建立格子之间的相互联系
{
paint[L(i,j)][st]=(str[j]=='y'?0:1);
paint[L(i,j)][L(i,j)]=1;
for(int k=0;k<4;k++)
{
int x=i+Find[k];
int y=j+Find[k+4];
if(x<0 || x>=N || y<0 || y>=N)
continue;
paint[L(i,j)][L(x,y)]=1;
}
}
}
Guass();
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MOD 7
int a[310][310];
int N,M;//M件物品,N个记录!!
char str1[5],str2[5];
int ans[310];
int solved(char s[])//额~此处可以优化
{
if(s[0]=='M') return 1;
if(s[0]=='T' && s[1]=='U') return 2;
if(s[0]=='W') return 3;
if(s[0]=='T' && s[1]=='H') return 4;
if(s[0]=='F') return 5;
if(s[0]=='S' && s[1]=='A') return 6;
if(s[0]=='S' && s[1]=='U') return 7;
}
int extend_gcd(int A,int B,int &x,int &y)//扩展gcd
{
if(B==0)
{
x=1,y=0;
return A;
}
else
{
int r=extend_gcd(B,A%B,x,y);
int t=x;
x=y;
y=t-A/B*y;
return r;
}
}
int lcm(int A,int B)//求最小公倍数
{
int x=0,y=0;
return A*B/extend_gcd(A,B,x,y);
}
void Guass()//高斯消元
{
int i,j,row,col;
for(row=0,col=0;row<N && col<M;row++,col++)
{
for(i=row;i<N;i++)
if(a[i][col]) break;
if(i==N)
{
row--;
continue;
}
if(i!=row)
for(j=0;j<=M;j++) swap(a[row][j],a[i][j]);
for(i=row+1;i<N;i++)
{
if(a[i][col])
{
int LCM=lcm(a[row][col],a[i][col]);//利用最小公倍数去化上三角
int ch1=LCM/a[row][col],ch2=LCM/a[i][col];
for(j=col;j<=M;j++)
a[i][j]=((a[i][j]*ch2-a[row][j]*ch1)%MOD+MOD)%MOD;
}
}
}
for(i=row;i<N;i++)//无解的情况
{
if(a[i][M]!=0)
{
printf("Inconsistent data.\n");
return ;
}
}
if(row<M)//有自由元的情况,则会出现多种解
{
printf("Multiple solutions.\n");
return ;
}
//当有唯一解时
for(i=M-1;i>=0;i--)
{
int ch=0;
for(j=i+1;j<M;j++)
{
ch=(ch+ans[j]*a[i][j]%MOD)%MOD;
}
int last=((a[i][M]-ch)%MOD+MOD)%MOD;
int x=0,y=0;
int d=extend_gcd(a[i][i],MOD,x,y);//利用扩展gcd求解
x%=MOD;
if(x<0) x+=MOD;
ans[i]=last*x/d%MOD;
if(ans[i]<3) ans[i]+=7;
}
for(int i=0;i<M;i++)
{
if(i==0)
printf("%d",ans[i]);
else
printf(" %d",ans[i]);
}
printf("\n");
}
int main()
{
while(scanf("%d%d",&M,&N),N||M)
{
memset(a,0,sizeof(a));
memset(ans,0,sizeof(ans));
int K;
for(int i=0;i<N;i++)
{
scanf("%d%s%s",&K,str1,str2);
int last=((solved(str2)-solved(str1)+1)%MOD+MOD)%MOD;
for(int j=0;j<K;j++)
{
int v;
scanf("%d",&v);
a[i][v-1]=(a[i][v-1]+1)%MOD;
}
a[i][M]=last;
}
Guass();
}
return 0;
}
注意
for(j=0;j<N;j++)
{
if(A[j][j]) continue;
for(k=j;k<N;k++)
if(A[j][k]) break;
if(k==N) break;
for(i=0;i<N;i++)
swap(A[i][j],A[i][k]);
}
void dfs(int u)//一开始传进来GUASS()得到的row
{
if(u==N)
{
for(int i=0;i<N;i++)
temp[i]=ans[i];
for(int i=row-1;i>=0;i--)
{
int ch=A[i][N];
for(int j=i+1;j<N;j++)
ch=ch^(temp[j] && A[i][j]);
temp[i]=ch;
}
int sum=0;
for(int i=0;i<N;i++)
sum+=temp[i];
maxn=min(maxn,sum);
return ;
}
ans[u]=0;
dfs(u+1);
ans[u]=1;
dfs(u+1);
}
POJ 1222 EXTENDED LIGHTS OUT
http://acm.pku.edu.cn/JudgeOnline/problem?id=1222
POJ 1681 Painter's Problem
http://acm.pku.edu.cn/JudgeOnline/problem?id=1681
POJ 1753 Flip Game
http://acm.pku.edu.cn/JudgeOnline/problem?id=1753
POJ 1830 开关问题
http://acm.pku.edu.cn/JudgeOnline/problem?id=1830
POJ 3185 The Water Bowls
http://acm.pku.edu.cn/JudgeOnline/problem?id=3185
POJ 2947 Widget Factory
http://acm.pku.edu.cn/JudgeOnline/problem?id=2947
POJ 1166 The Clocks
http://acm.pku.edu.cn/JudgeOnline/problem?id=1166
POJ 2065 SETI
http://acm.pku.edu.cn/JudgeOnline/problem?id=2065
POJ 1487 Single-Player Games
http://acm.pku.edu.cn/JudgeOnline/problem?id=1487