学习高斯消元

点击打开链接     习题  行列式

高斯消元问题类型:

用LCM 保持整型

1. 基本的高斯消元,裸模板 HDU3359

2. 开关问题,用^操作代替 -, 求x[i]时候一样用*  poj 1222 1830 1753

3. 枚举自由变元, return -1 是因为出现[0,0,0,0,a]这种情况,return 0 是唯一解,否则是有自由变元

4. 取模方程 (a1*x1+a2*x2...)%P=b在初等行变换后,每次进行消元的时候将所有值模P,最后求解回带的时候利用扩展欧几里得来对每一个ai求一个最小的可行解

3*a4 % P = t4,可以表示成3*a4 + K*P = t4  ,d=exgcd(a[i][i],mod,x,y); ans=ans/d*x;    poj 2947

5. 线性基问题,异或运算中求可组成的第K大数.每个数就是equ   二进制位数为var ,消元成线性基. 比如n个数字,m个线性基.组成2^(n-m)个数字.这个K的二进制形式每个位

的权重刚好是线性基的顺序.如果有 0行,则0为第一小. 点击打开链接      SGU 275

6. 求电阻.依据KCL定理.每个节点电流流入流出相等.电路图是双向图,要从两个方面考虑.依据电流列等式,X[i]是电压.再设定一个0电压处.S流入为1,T流入为-1.

电流流出为正,流入为负(相反也行),x[u][v]++,x[v][u]++,x[u][u]--,x[v][v]--; 表示u这个点流入流出和值为0电流是双向的,所以双向. HDU 5006 HDU 3976 点击打开链接 点击打开链接

求解线性方程的结果会出现三种情况:无解,多解和唯一解。看下图

        

当某一行出现(0,0,……0,a) 时,方程无解。因为x1*0+x2*0+……+xn*0=a(a不为0)等式无解

当从某一行开始至最后一行,出现(0,0,……0)说明方程存在自由元,则会出现多解

当矩阵的秩等于等式个数时,有唯一解

poj 1753

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-8
const int MAXN=17;
int N,M,T;
int a[MAXN][MAXN],x[MAXN];
int free_x[MAXN],x_num;
int equ,var;
int Gauss(int (*a)[MAXN]){
    int row,col;
    x_num=0;
    for(row=0,col=0;row<equ && col<var;row++,col++){
        int mxr = row;
        for(int i=row+1;i<equ;i++)
            if( fabs(a[i][col]) - fabs(a[mxr][col]) >eps )
                mxr=i;
        if(mxr != row)
            for(int i=row;i<var+1;i++) swap(a[row][i],a[mxr][i]);///
        if(fabs(a[row][col])< eps){
            free_x[x_num++]=col;row--;continue;
        }
        for(int i=row+1;i<equ;i++) if(fabs(a[i][col])>eps){
            for(int j=col;j<var+1;j++)
                a[i][j] ^= a[row][j];
        }
    }

    for(int i=row;i<equ;i++)
        if(a[i][var]>0) return -1;
    if(row<var) return var-row;
    for(int i=var-1;i>=0;i--) if(a[i][i]){
        x[i]=a[i][var];
        for(int j=i+1;j<var;j++) x[i]^=(a[i][j] * x[j]);
    }
    return 0;
}
char G[4][4];
int b[MAXN][MAXN];
int solve(int (*a)[MAXN]){
    int t=Gauss(a);
    int ans=0;
    if(t==-1) return inf;
    if(t==0) {
        for(int i=0;i<var;i++) if(x[i]) ans++;
        return ans;
    }
    ///枚举自由变元
    ans=inf;
    for(int i=0;i<(1<<t);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++)
                x[idx] ^=a[j][l] * x[l];
            cnt+=x[idx];
        }
        ans=min(ans,cnt);
    }
    return ans;
}
int main()
{
    equ=16,var=16;
    for(int i=0;i<4;i++)
       gets(G[i]);
    int ans=inf;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<16;i++){
        a[i][i]=b[i][i]=1;
        if(G[i/4][i%4]=='b') a[i][16]=0,b[i][16]=1;
        else a[i][16]=1,b[i][16]=0;

    }
    for(int i = 0;i < 4;i++)
        for(int j = 0;j < 4;j++){
            int t = i*4+j;
            if(i > 0)b[(i-1)*4+j][t]=a[(i-1)*4+j][t] = 1;
            if(i < 3)b[(i+1)*4+j][t]=a[(i+1)*4+j][t] = 1;
            if(j > 0)b[i*4+j-1][t]=a[i*4+j-1][t] = 1;
            if(j < 3)b[i*4+j+1][t]=a[i*4+j+1][t] = 1;
        }
//        for(int i=0;i<16;i++)printf("%d ",a[i][16]);cout<<endl;
//        for(int i=0;i<16;i++)printf("%d ",b[i][16]);cout<<endl;
    ans=solve(a);
    ans=min(ans,solve(b));
    if(ans==inf) printf("Impossible\n");
    else printf("%d\n",ans);

    return 0;
}

poj 2947

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-8
const int MAXN=400;
int N,M,T;
int a[MAXN][MAXN],x[MAXN];
int free_x[MAXN],x_num;
int equ,var;
inline int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
inline int lcm(int a,int b){
    return a/gcd(a,b)*b;
}
int expgcd(int a,int b,int &x,int &y){
    int q,tmp;
    if(b==0){
        q=a;x=1;y=0;
        return q;
    }
    q=expgcd(b,a%b,x,y);
    tmp=x;x=y;
    y=tmp-(a/b)*y;
    return q;
}

int Gauss(int (*a)[MAXN]){
    int row,col;
    x_num=0;
    for(int i=0;i<=var;i++)
        free_x[i]=1;
    for(row=0,col=0;row<equ && col<var;row++,col++){
        int mxr = row;
        for(int i=row+1;i<equ;i++)
            if( fabs(a[i][col]) - fabs(a[mxr][col]) >eps )
                mxr=i;
        if(mxr != row)
            for(int i=row;i<var+1;i++) swap(a[row][i],a[mxr][i]);///
        if(fabs(a[row][col])< eps){
            free_x[x_num++]=col;row--;continue;
        }
        for(int i=row+1;i<equ;i++) if(fabs(a[i][col])>eps){
            int LCM=lcm(abs(a[i][col]),abs(a[row][col]));
            int ta=LCM/abs(a[i][col]);
            int tb=LCM/abs(a[row][col]);
            ///if(a[i][col]*a[row][col]<0) tb=-tb;
            for(int j=col;j<var+1;j++)
                a[i][j] = ((a[i][j]*ta-a[row][j]*tb)%7+7)%7;
        }///用LCM的方法是因为要保持整型
    }

    for(int i=row;i<equ;i++)
        if(a[i][var]>0) return -1;
    if(row<var){///这样标记自由变元的方法避免了列移动
        for(int k=row-1;k>=0;k--){
            x_num=0;
            int idx;
            for(int j=0;j<var;j++)
                if(a[k][j]>eps && free_x[j]) x_num++,idx=j;
            if(x_num>1) continue;
            int tmp=a[k][var];
            for(int j=0;j<var;j++) if(a[k][j]>eps && j!=idx)
                    tmp =((tmp - a[k][j]*x[j]%7)+7)%7;
            x[idx]=(tmp/a[k][idx])%7;
            free_x[idx]=0;
        }
        return var-row;
    }
    for(int i=var-1;i>=0;i--){
        int tmp=a[i][var];
        for(int j=i+1;j<var;j++)
            tmp =((tmp - a[i][j]*x[j]%7)+7)%7;
        while(tmp%a[i][i]) tmp+=7;
        x[i]=(tmp/a[i][i])%7;
        if(x[i]<3) x[i]+=7;
    }
    return 0;
}

int solve(int (*a)[MAXN]) {
    int t=Gauss(a);
    int ans=0;
    if(t==-1) return inf;
    if(t==0) {
        for(int i=0;i<var;i++) if(x[i]) ans++;
        return ans;
    }
    ///枚举自由变元
    ans=inf;
    for(int i=0;i<(1<<t);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++)
                x[idx] ^=a[j][l] * x[l];
            cnt+=x[idx];
        }
        ans=min(ans,cnt);
    }
    return ans;
}
int tans(char *s){
    if(s[0]=='M') return 1;
    else if(s[0]=='W') return 3;
    else if(s[0]=='F') return 5;
    else if(s[0]=='T' && s[1]=='U') return 2;
    else if(s[0]=='T' && s[1]=='H') return 4;
    else if(s[0]=='S' && s[1]=='A') return 6;
    else return 7;
}
int main() {
    while(~scanf("%d%d",&N,&M) && N+M){
        memset(a,0,sizeof(a));
        for(int i=0;i<M;i++){
            int n;
            char s1[10],s2[10];
            scanf("%d%s%s",&n,s1,s2);
            a[i][N]=(tans(s2)-tans(s1)+8)%7 ;
            for(int j=0;j<n;j++){
                int t;
                scanf("%d",&t);
                a[i][--t]++;
                a[i][t]%=7;
            }
        }
        equ=M,var=N;
        int ans=Gauss(a);
        if(ans==-1) puts("Inconsistent data.");
        else if(ans>0) puts("Multiple solutions.");
        else {
            for(int i=0;i<N;i++)
                if(i==N-1) printf("%d\n",x[i]);
                else printf("%d ",x[i]);
        }
    }

    return 0;
}

HDU3976

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
const double eps = 1e-8 ;
using namespace std;

int T ,cas ,N,M;
double mat[55][55] ;
double ans[55] ;

void gauss(){
	int row, col ;
	row = col = 0 ;
	for( ;row<N && col<N;row++,col++){
		int max_r = row ;
		for(int i=row+1;i<N;i++){
			if(fabs(mat[max_r][col]) < fabs(mat[i][col]) )	max_r = i ;
		}
		if(max_r != row){
			for(int j=col;j<=N;j++){
				swap(mat[row][j] ,mat[max_r][j] );
			}
		}
		for(int i=row+1;i<N;i++){
			if(fabs(mat[i][col]) < eps)	continue ;
			double a = - mat[i][col] / mat[row][col] ;
			for(int j=col;j<=N;j++){
				mat[i][j] += mat[row][j]*a ;
			}
		}
	}
	memset(ans , 0 ,sizeof(ans)) ;
	for(int i=row-2;i>=0;i--){
		double res = mat[i][N] ;
		for(int j=i+1;j<N;j++){
			res -= mat[i][j]*ans[j];
		}
		ans[i] = res / mat[i][i] ;
	}
	printf("%.2f\n",ans[0]-ans[N-1]);
}
int main(){
	scanf("%d",&T);
	cas = 0 ;
	while(T--){
		++cas  ;
		scanf("%d %d",&N,&M);
		memset(mat , 0 ,sizeof(mat));
		for(int i=0;i<M;i++){
			int a,b, c;
			scanf("%d %d %d",&a,&b,&c);
			a -- ; b-- ;
			mat[a][a] -= 1.0/(c*1.0) ;
			mat[b][b] -= 1.0/(c*1.0) ;
			mat[a][b] += 1.0/(c*1.0) ;
			mat[b][a] += 1.0/(c*1.0) ;
		}
		mat[0][N] = -1 ;
		mat[N-1][N] = 1 ;
		printf("Case #%d: ",cas);
		gauss() ;
	}
	return 0;
}
时间: 2024-11-08 23:34:07

学习高斯消元的相关文章

hdu6465 高斯消元

题目链接:水题 高斯消元学习 高斯消元模板 题解:来自官方 1 #include<bits/stdc++.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<

ACM学习历程—HDU 3915 Game(Nim博弈 &amp;&amp; xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915 题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势. 首先这是个Nim博弈,必败局势是所有xor和为0. 那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数. 首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的. 所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数. 对n==row特判一下. 代码:

ACM学习历程—HDU 3949 XOR(xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 题目大意是给n个数,然后随便取几个数求xor和,求第k小的.(重复不计算) 首先想把所有xor的值都求出来,对于这个规模的n是不可行的. 然后之前有过类似的题,求最大的,有一种方法用到了线性基. 那么线性基能不能表示第k大的呢? 显然,因为线性基可以不重复的表示所有结果.它和原数组是等价的. 对于一个满秩矩阵 100000 010000 001000 000100 000010 000001

poj_1222_高斯消元

第一次学习使用高斯消元,将灯板化为线性方程组,进行求解. /*######################################################################### # File Name: poj_1222.cpp # Author: CaoLei # Created Time: 2015/7/20 15:48:04 ###################################################################

【BZOJ-1923】外星千足虫 高斯消元 + xor方程组

1923: [Sdoi2010]外星千足虫 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 766  Solved: 485[Submit][Status][Discuss] Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用“点足机”的统计结果.每行包含一个“01”串和一个数字,用一个空格隔开.“01”串按位依次表示每只虫子是否被放入机器:如果第 i 个字符是“0”则代表编号为

线代之高斯消元

数学上,高斯消元法(或译:高斯消去法),是线性代数规划中的一个算法,可用来为线性方程组求解.但其算法十分复杂,不常用于加减消元法,求出矩阵的秩,以及求出可逆方阵的逆矩阵.不过,如果有过百万条等式时,这个算法会十分省时.一些极大的方程组通常会用迭代法以及花式消元来解决.当用于一个矩阵时,高斯消元法会产生出一个"行梯阵式".高斯消元法可以用在电脑中来解决数千条等式及未知数.亦有一些方法特地用来解决一些有特别排列的系数的方程组. 2968: Lights  Time Limit(Common

矩阵算法 高斯消元 行列式 矩阵的秩

今天学习一下矩阵的基本算法 高斯消元是解线性方程组的有力工具. 基本思想是通过将增广矩阵经过行初等变化变成简化阶梯形矩阵. 下面采用的是列主元高斯消元法,复杂度为O(n^3). 很容易根据高斯消元法的过程得出行列式和秩的算法. 代码: /********************************************************* * ------------------ * * author AbyssalFish * ***************************

高斯消元 初见

今天,跟着HYM大神学习了高斯消元,思想很简单,不过用处很大,也有一些细节. 其实就是消元的思想,对n个方程不断消元,在解出一个未知数之后,回带求出其他未知数.如果回带时,我们发现方程左面为0,右面不为0,则无解:若左面为0,右面为0,则多解. cogs1845||bzoj1013 球星空间生成器sphere 题目大意:给出n维空间内一个球上的n+1个点,求圆心坐标. 思路:比较裸的高斯消元,唯一就是自己建方程.设圆心坐标(a,b,c,d,...),我们发现,球上各点到圆心距离相等,于是就有连等

BZOJ 3569 DZY Loves Chinese II 高斯消元

题目大意:给定一个[魞歄连通图],多次询问当图中某k条边消失时这个图是否联通 强制在线 我们找到这个图的任意一棵生成树 然后对于每条非树边将其的权值赋为一个随机数 对于每条树边 我们将这条树边的权值设为所有覆盖这条树边的边权的异或和 那么图不连通当且仅当删除一条树边和覆盖这条树边的所有边集 而由于刚才的处理一条树边和覆盖这条边的所有边集的异或和为零 于是问题转化成了对于给定的k条边是否存在一个边权的异或和为零的子集 果断高斯消元 由于使用了随机化所以碰撞率极低 好方法学习了...构思真是巧妙 记