POJ 1830 開關問題 高斯消元

題意:給你N個開關,其中某些開關之間是相互影響的,即一個開關控制多個,那麼每個開關操作與否爲一個變元,有N個變元,開關之間相互影響的係數設爲1,否則爲0,對模2高斯消元求解自由變元個數。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=30;
int n,m;//有n個方程,m個未知數
int a[maxn][maxn];
int x[maxn];//解集
bool free_x[maxn];//判斷是否爲自由變元
int free_num;//記錄自由變元的個數

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

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


//返回-2表示有浮點數解,但無整數解;返回-1表示無解;返回fjfj0表示有唯一解;返回1表示有無窮個解
int gauss()
{
    int i,j,k;
    int max_r;//當前這列絕對值最大的行
    int col;//當前處理的列
    int ta,tb;
    int LCM;
    int temp;
    int free_x_num;
    int free_index;
    col=0;
    for(k=0;k<n&&col<m;k++,col++)
    {//枚舉當前處理的行
        max_r=k;
        for(i=k+1;i<n;i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
        }
        if(max_r!=k)
        {//與第k行交換
            for(j=k;j<m+1;j++) swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0)
        {//說明該col列第k行以下全都是0了,則處理當前行的下一列
            k--;
            continue;
        }
        for(i=k+1;i<n;i++)
        {//枚舉要刪去的行
            if(a[i][col]!=0)
            {
                LCM=lcm(abs(a[i][col]),abs(a[k][col]));
                ta=LCM/abs(a[i][col]),tb=LCM/abs(a[k][col]);
                if(a[i][col]*a[k][col]<0) ta=-tb;//異號的情況是兩個數相加
                for(j=col;j<m+1;j++)
                {
                    a[i][j]=((a[i][j]*ta)%2-(a[k][j]*tb)%2+2)%2;
                }
            }
        }
    }
    for(i=k;i<n;i++)
    {
        if(a[i][col]!=0) return -1;
    }
    if(k<m)
    {
        for(i=k-1;i>=0;i--)
        {
            free_x_num=0;
            for(j=0;j<m;j++)
            {
                if(a[i][j]!=0&&free_x[j]) free_x_num++,free_index=j;
            }
            if(free_x_num>1) continue;
            temp=a[i][m];
            for(j=0;j<m;j++)
            {
                if(a[i][j]!=0&&j!=free_index) temp-=a[i][j]*x[j];
            }
            x[free_index]=temp/a[i][free_index];
            free_x[free_index]=0;
        }
        return m-k;//自由變元有m-k個
    }
    for(i=m-1;i>=0;i--)
    {
        temp=a[i][m];
        for(j=i+1;j<m;j++)
        {
            if(a[i][j]!=0) temp-=a[i][j]*x[j];
        }
        if(temp%a[i][i]!=0) return -2;
        x[i]=temp/a[i][i];
    }
    return 0;
}

int c[maxn],t[maxn];

int main()
{
    int k,x,y;
    scanf("%d",&k);
    while(k--)
    {
        memset(a,0,sizeof a);
        memset(free_x,1,sizeof free_x);
        scanf("%d",&m);
        n=m;
        for(int i=0;i<m;i++) a[i][i]=1;
        for(int i=0;i<m;i++) scanf("%d",&c[i]);
        for(int i=0;i<m;i++) scanf("%d",&t[i]);
        while(scanf("%d%d",&x,&y))
        {
            if(x==0&&y==0) break;
            a[y-1][x-1]=1;
        }
        for(int i=0;i<n;i++)
        {
            a[i][m]=(t[i]-c[i]+2)%2;
        }
        free_num=gauss();
        //cout<<"自由變元個數:"<<free_num<<endl;
        if(free_num==-1||free_num==-2) puts("Oh,it's impossible~!!");
        else printf("%d\n",(1<<free_num));
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章