Guass(高斯消元+模板)

複雜度(O(n3)
過程:先將增廣矩陣轉上三角矩陣,然後解x[i];

模板:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;

ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}

ll lcm(ll a,ll b)
{
    return a/gcd(a,b)*b;
}

const int maxn=105;

int equ,var;
int x[maxn];
int a[maxn][maxn];//增廣矩陣
int free_x[maxn];
int free_num=0;

int Gauss()//O(n^3)
{
    int col,row,max_r;
    col=0;row=0;
    free_num=0;
    for(;row<equ&&col<var;row++,col++)
    {
        max_r=row;
        for(int i=row+1;i<equ;i++)//找出列中最大的行,然後交換
        {
            if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
        }
        if(max_r!=row)
        {
            for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
        }
        if(a[row][col]==0)//如果本列row行一下全0則不需要在處理,直接下一列
        {
            row--;
            free_x[free_num++]=col;//自由變元
            continue;
        }
        for(int i=row+1;i<equ;i++)//初等矩陣變換,目的上三角矩陣
        {
            if(a[i][col]!=0)
            {
                int t=lcm(abs(a[i][col]),abs(a[row][col]));
                int ta=t/a[row][col];
                int tb=t/a[i][col];
                if(a[row][col]*a[i][col]>0)tb=-tb;
                for(int j=col;j<var+1;j++)
                {
                    a[i][j]=a[i][j]*tb+a[row][j]*ta;
                }
            }
        }
    }
    for(int i=row;i<equ;i++)//row行一下肯定已經全0了,如果var不爲0,則無解
    {
        if(a[i][col]!=0)return -1;
    }
    if(row<var)return var-row;//有多少行0既有多少個自由元
    for(int i=var-1;i>=0;i--)//解上三角矩陣,自下而上
    {
        int t = a[i][var];
        for(int j=i+1;j<var;j++)
        {
            t-=a[i][j]*x[j];
        }
        if(t%a[i][i]!=0)return -2;
        else x[i]=t/a[i][i];
    }
    return 0;
}
int main()
{
    while(scanf("%d%d",&equ,&var)!=EOF)
    {
        memset(a,0,sizeof a);
        memset(x,0,sizeof x);
        memset(free_x,0,sizeof free_x);
        for(int i=0;i<equ;i++)
        {
            for(int j=0;j<=var;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        int free=Gauss();
        if(free==-1)
        {
            printf("無解\n");
        }
        else if(free==-2)
        {
            printf("無整數解,有浮點數解\n");
        }
        else if(free>0)
        {
            printf("自由元個數爲%d\n",free);
        }
        else
        {
            for(int i=0;i<var;i++)
            {
                printf("x%d: %d\n",i+1,x[i]);
            }
        }
    }
    return 0;
}

poj1830
題解:構造成模2的解方程組。做幾個等價即可,乘法等價乘&&,加法減法等價乘^

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;

const int maxn=105;

int equ,var;
int x[maxn];
int a[maxn][maxn];//增廣矩陣
int free_x[maxn];
int free_num;

int Gauss()//O(n^3)
{
    int col,row,max_r;
    col=0;row=0;
    free_num=0;
    for(;row<equ&&col<var;row++,col++)
    {
        max_r=row;
        for(int i=row+1;i<equ;i++)//找出列中最大的行,然後交換
        {
            if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
        }
        if(max_r!=row)
        {
            for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
        }
        if(a[row][col]==0)//如果本列row行一下全0則不需要在處理,直接下一列
        {
            row--;
            free_x[free_num++]=col;//記錄自由變元
            continue;
        }
        for(int i=row+1;i<equ;i++)//初等矩陣變換,目的上三角矩陣
        {
            if(a[i][col]!=0)
            for(int j=col;j<var+1;j++)
            {
                a[i][j]=a[i][j]^a[row][j];
            }
        }
    }
    for(int i=row;i<equ;i++)//row行一下肯定已經全0了,如果var不爲0,則無解
    {
        if(a[i][col]!=0)return -1;
    }
    if(row<var)return var-row;//有多少行0既有多少個自由元
    for(int i=var-1;i>=0;i--)//解上三角矩陣,自下而上
    {
        x[i] = a[i][var];
        for(int j=i+1;j<var;j++)
        {
            x[i]^=(a[i][j]&&x[j]);
        }
    }
    return 0;
}
int start[40],end[40];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof a);
        memset(x,0,sizeof x);
        equ=var=n;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&start[i]);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%d",&end[i]);
        }
        int ca,cb;
        while(scanf("%d%d",&ca,&cb))//題意ca變則cb變,即ans[cb]的結果受ca的影響
        {
            if(ca==0&&cb==0)break;
            a[cb-1][ca-1]=1;//注意
        }
        for(int i=0;i<n;i++)
        {
            a[i][i]=1;
            a[i][n]=(start[i]^end[i]);
        }
        int free=Gauss();
        if(free==-1)
        {
            printf("Oh,it's impossible~!!\n");
        }
        else
        {
            printf("%d\n",1<<free);
        }
    }
    return 0;
}

poj1681

題意:對所有塊塗顏色,只有黃白,每次塗一快,上下左右顏色反轉,求最後塗成全黃要幾步。
題解:構造高斯消元,求解中爲1的個數。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;

const int maxn=255;

int equ,var;
int x[maxn];
int a[maxn][maxn];//增廣矩陣
int free_x[maxn];
int free_num;

int Gauss()//O(n^3)
{
    int col,row,max_r;
    col=0;row=0;
    free_num=0;
    for(;row<equ&&col<var;row++,col++)
    {
        max_r=row;
        for(int i=row+1;i<equ;i++)//找出列中最大的行,然後交換
        {
            if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
        }
        if(max_r!=row)
        {
            for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
        }
        if(a[row][col]==0)//如果本列row行一下全0則不需要在處理,直接下一列
        {
            row--;
            free_x[free_num++]=col;//記錄自由變元
            continue;
        }
        for(int i=row+1;i<equ;i++)//初等矩陣變換,目的上三角矩陣
        {
            if(a[i][col]!=0)
            for(int j=col;j<var+1;j++)
            {
                a[i][j]=a[i][j]^a[row][j];
            }
        }
    }
    for(int i=row;i<equ;i++)//row行一下肯定已經全0了,如果var不爲0,則無解
    {
        if(a[i][col]!=0)return -1;
    }
    //注意我們這裏把自由變元刪掉
    for(int i=var-1;i>=0;i--)//解上三角矩陣,自下而上
    {
        x[i] = a[i][var];
        for(int j=i+1;j<var;j++)
        {
            x[i]^=(a[i][j]&&x[j]);
        }
    }
    return 0;
}
char str[50][50];
int t,n;
void init()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            int t=i*n+j;
            a[t][t]=1;
            if(i>0)a[(i-1)*n+j][t]=1;
            if(j>0)a[i*n+j-1][t]=1;
            if(i<n-1)a[(i+1)*n+j][t]=1;
            if(j<n-1)a[i*n+j+1][t]=1;
        }
    }
}
int main()
{

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof a);
        memset(x,0,sizeof x);
        memset(free_x,0,sizeof free_x);
        equ=var=n*n;
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
        }

        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(str[i][j]=='y')
                {
                    a[i*n+j][var]=0;
                }
                else
                {
                    a[i*n+j][var]=1;
                }
            }
        }
        init();

        int free=Gauss();
        if(free==-1)
        {
            printf("inf\n");
        }
        else
        {
            int sum=0;
            for(int i=0;i<var;i++){
                if(x[i])sum++;
            }
            printf("%d\n",sum);
        }
    }
    return 0;
}

上面的程序可能出錯:
比較嚴謹的做法是:枚舉自由變元求最小

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;

const int maxn=255;

int equ,var;
int x[maxn];
int a[maxn][maxn];//增廣矩陣
int free_x[maxn];
int free_num;

int Gauss()//O(n^3)
{
    int col,row,max_r;
    col=0;row=0;
    free_num=0;
    for(;row<equ&&col<var;row++,col++)
    {
        max_r=row;
        for(int i=row+1;i<equ;i++)//找出列中最大的行,然後交換
        {
            if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
        }
        if(max_r!=row)
        {
            for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
        }
        if(a[row][col]==0)//如果本列row行一下全0則不需要在處理,直接下一列
        {
            row--;
            free_x[free_num++]=col;//記錄自由變元
            continue;
        }
        for(int i=row+1;i<equ;i++)//初等矩陣變換,目的上三角矩陣
        {
            if(a[i][col]!=0)
            for(int j=col;j<var+1;j++)
            {
                a[i][j]=a[i][j]^a[row][j];
            }
        }
    }
    for(int i=row;i<equ;i++)//row行一下肯定已經全0了,如果var不爲0,則無解
    {
        if(a[i][col]!=0)return -1;
    }
    //注意我們這裏把自由變元刪掉
    for(int i=var-1;i>=0;i--)//解上三角矩陣,自下而上
    {
        x[i] = a[i][var];
        for(int j=i+1;j<var;j++)
        {
            x[i]^=(a[i][j]&&x[j]);
        }
    }
    int stat=1<<(var-row);//自由變元有 var-k 個
    int res=1e9;
    for(int i=0;i<stat;i++)//枚舉所有變元
    {
        int cnt=0;
        int index=i;
        for(int j=0;j<var-row;j++)
        {
            x[free_x[j]]=(index&1);
            if(x[free_x[j]]) cnt++;
            index>>=1;
        }
        for(int j=row-1;j>=0;j--)
        {
            int tmp=a[j][var];
            for(int l=j+1;l<var;l++)
              if(a[j][l]) tmp^=x[l];
            x[j]=tmp;
            if(x[j])cnt++;
        }
        if(cnt<res)res=cnt;
    }
    return res;
}
char str[50][50];
int t,n;
void init()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            int t=i*n+j;
            a[t][t]=1;
            if(i>0)a[(i-1)*n+j][t]=1;
            if(j>0)a[i*n+j-1][t]=1;
            if(i<n-1)a[(i+1)*n+j][t]=1;
            if(j<n-1)a[i*n+j+1][t]=1;
        }
    }
}
int main()
{

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof a);
        memset(x,0,sizeof x);
        memset(free_x,0,sizeof free_x);
        equ=var=n*n;
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
        }

        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(str[i][j]=='y')
                {
                    a[i*n+j][var]=0;
                }
                else
                {
                    a[i*n+j][var]=1;
                }
            }
        }
        init();

        int free=Gauss();
        if(free==-1)
        {
            printf("inf\n");
        }
        else
        {
            printf("%d\n",free);
        }
    }
    return 0;
}
發佈了45 篇原創文章 · 獲贊 27 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章