hdu 5755(高斯消元——模线性方程组模板)

PS. 看了大神的题解,发现确实可以用m个未知数的高斯消元做。因为确定了第一行的情况,之后所有行的情况都可以根据第一行推。 这样复杂度直接变成O(m*m*m)

 

知道了是高斯消元后,其实只要稍加处理,就可以解决带模的情况。

1 是在进行矩阵行变化的时候,取模。

2 最后的除法用逆元。(因为a[i][i]必定非0 且小于模数) 

然后对于无穷多解的情况,只需要将那些列全为0的未知数定义一个固定值。(这里设的是0)其余操作不变。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 1010
using namespace std;
//freopen("din.txt","r",stdin);

int a[N][N],X[N];//分别记录增广矩阵和解集
int free_x[N];//记录自由变量
int equ,var;//分别表示方程组的个数和变量的个数

int GCD(int x,int y){
    if (y == 0) return x;
    return GCD(y,x%y);
}
int LCM(int x,int y){
    return x/GCD(x,y)*y;
}
void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}
// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,
//但无整数解,-1表无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,
//并返回自由变元的个数)

//ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){d=a;x=1;y=0;return;}
    extendgcd(b,a%b,d,y,x);
    y-=x*(a/b);
}

//Ax=1(mod M),gcd(A,M)==1
//输入:10^18>=A,M>=1
//输出:返回x的范围是[1,M-1]
ll GetNi(ll A,ll MM)
{
    ll rex=0,rey=0;
    ll td=0;
    extendgcd(A,MM,td,rex,rey);
    return (rex%MM+MM)%MM;
}

int Guass(){
    int i,j,k,col;
    CL(X,0); CL(free_x,1);
    
    for (k = 0,col = 0; k < equ && col < var; k++, col++){
        int max_r = k;
        for (i = k + 1; i < equ; ++i){
            if (iabs(a[i][col]) > iabs(a[max_r][col])) max_r = i;
        }
        if (max_r != k){
            for (i = k; i < var + 1; ++i) swap(a[k][i],a[max_r][i]);
        }
        if (a[k][col] == 0){
            //可以随意定义的变量
            X[col] = 0;//强制赋值为0
            free_x[col] = 0;
            k--;
            //cout<<k<<endl;
            continue;
        }
        for (i = k + 1; i < equ; ++i){
            if (a[i][col] != 0){
                int lcm = LCM(a[k][col],a[i][col]);
                int ta = lcm/iabs(a[i][col]); int tb = lcm/iabs(a[k][col]);
                if (a[i][col]*a[k][col] < 0) tb = -tb;
                for (j = col; j < var + 1; ++j){
                    a[i][j] = ((ta*a[i][j] - tb*a[k][j])%3+3)%3;
                }
            }
        }
    }
    //Debug();
    // 1. 无解的情况:
    for (i = k; i < equ; ++i){
        if (a[i][col] != 0) return -1;
    }
    // 2. 无穷解的情况:
    if (k < var){
        
        int num = 0,freeidx=0;
        for (i = k - 1; i >= 0; --i){
            num = 0;
            int tmp = a[i][var];
            for (j = 0; j < var; ++j){
                if (a[i][j] != 0 && free_x[j]){
                    num++;
                    freeidx = j;
                }
            }
            if (num > 1) continue;
            tmp = a[i][var];
            for (j = 0; j < var; ++j){
                if (a[i][j] && j != freeidx) tmp -= a[i][j]*X[j];
            }
            //这里也要
            
            int k2 = (tmp%3+3)%3;
            int k1 = (a[i][freeidx]%3+3)%3;
            if(k1!=0)
            {
                X[freeidx] = k2*(int)GetNi(k1, 3);
            }
            else
            {
                X[freeidx] = 0;
                //printf("X[%d]为任意?\n",i);
            }
            
            //X[freeidx] = tmp/a[i][freeidx];
            free_x[freeidx] = 0;
        }
        return var - k;
    }
    // 3. 唯一解的情况:
    for (i = k - 1; i >= 0; --i){
        int tmp = a[i][var];
        for (j = i + 1; j < var; ++j){
            tmp -= a[i][j]*X[j];
        }
        //强行搞一发
        int k2 = (tmp%3+3)%3;
        int k1 = (a[i][i]%3+3)%3;
        if(k1!=0)
        {
            X[i] = k2*(int)GetNi(k1, 3);
        }
        else
        {
            X[i] = 0;
            //printf("X[%d]为任意?\n",i);
        }
        //X[i] = tmp/a[i][i];//不整除?
    }
    return 0;
}


int g[33][33];

int getid(int i,int j,int n,int m)
{
    return (i-1)*m + (j-1);
}
int up[4]={1,-1,0,0};
int rl[4]={0,0,1,-1};

int main(){
    //freopen("din.txt","r",stdin);
    int i,j;
    
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                scanf("%d",&g[i][j]);
        equ = n*m;
        var = n*m;
        
        memset(a,0,sizeof(a));
        
        int id = 0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            {
                for(int k=0;k<4;k++)
                {
                    int ti = i+up[k];
                    int tj = j+rl[k];
                    if( ti>=1&&ti<=n && tj>=1&&tj<=m )
                    {
                        int tid = getid(ti, tj, n, m);
                        a[id][tid] = 1;
                    }
                }
                
                a[id][id] = 2;
                a[id][n*m] = (3-g[i][j])%3;
                id++;
            }
        CL(X,0);
        CL(free_x,0);
        //for (i = 0; i < equ; ++i)
            //for (j = 0; j < var + 1; ++j) scanf("%d",&a[i][j]);
        //Debug();
        
        int free_num = Guass();
        
        if (free_num == -1) printf("无解!\n");
        else if (free_num == -2) printf("无整数解\n");
        else {
//        else if (free_num > 0){
        
            //printf("无穷多解! 自由变元个数为%d\n", free_num);
            //我懂了,我需要确定free_num个数
//            for (i = 0; i < var; ++i){
//                if (free_x[i]) printf("X%d 是不确定的\n",i + 1);
//                else printf("X%d %d\n",i + 1,X[i]);
//            }
            
            
//        }
//        else{
            //我觉得可以!
            int ans = 0;
            for (i = 0 ; i < var; ++i){
                if(X[i]%3 != 0) ans += (X[i]%3+3)%3;
                //printf("X%d %d\n",i + 1,X[i]);
            }
            printf("%d\n",ans);
            for(i=0;i<var;i++)
            {
                int tmp =  (X[i]%3+3)%3;
                for(j=0;j<tmp;j++)
                {
                    int x,y;
                    x = i/m;
                    y = i%m;
                    x++; y++;
                    printf("%d %d\n",x,y);
                }
            }
        }
        //printf("\n");
    }
    return 0;
}
/*
 10
 3 3
 0 0 0
 0 0 0
 0 0 1
 1 2
 0 0
 2 30
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 */

 

2. m个未知数的情况

//
//  main.cpp
//  hdu5755.1
//
//  Created by New_Life on 16/8/4.
//  Copyright &#169; 2016年 chenhuan001. All rights reserved.
//

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 33
using namespace std;
//freopen("din.txt","r",stdin);

int a[N][N],X[N];//分别记录增广矩阵和解集
int free_x[N];//记录自由变量
int equ,var;//分别表示方程组的个数和变量的个数

int GCD(int x,int y){
    if (y == 0) return x;
    return GCD(y,x%y);
}
int LCM(int x,int y){
    return x/GCD(x,y)*y;
}
void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}
// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,
//但无整数解,-1表无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,
//并返回自由变元的个数)

//ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){d=a;x=1;y=0;return;}
    extendgcd(b,a%b,d,y,x);
    y-=x*(a/b);
}

//Ax=1(mod M),gcd(A,M)==1
//输入:10^18>=A,M>=1
//输出:返回x的范围是[1,M-1]
ll GetNi(ll A,ll MM)
{
    ll rex=0,rey=0;
    ll td=0;
    extendgcd(A,MM,td,rex,rey);
    return (rex%MM+MM)%MM;
}

int Guass(){
    int i,j,k,col;
    CL(X,0); CL(free_x,1);
    
    for (k = 0,col = 0; k < equ && col < var; k++, col++){
        int max_r = k;
        for (i = k + 1; i < equ; ++i){
            if (iabs(a[i][col]) > iabs(a[max_r][col])) max_r = i;
        }
        if (max_r != k){
            for (i = k; i < var + 1; ++i) swap(a[k][i],a[max_r][i]);
        }
        if (a[k][col] == 0){
            //可以随意定义的变量
            X[col] = 0;//强制赋值为0
            free_x[col] = 0;
            k--;
            //cout<<k<<endl;
            continue;
        }
        for (i = k + 1; i < equ; ++i){
            if (a[i][col] != 0){
                int lcm = LCM(a[k][col],a[i][col]);
                int ta = lcm/iabs(a[i][col]); int tb = lcm/iabs(a[k][col]);
                if (a[i][col]*a[k][col] < 0) tb = -tb;
                for (j = col; j < var + 1; ++j){
                    a[i][j] = ((ta*a[i][j] - tb*a[k][j])%3+3)%3;
                }
            }
        }
    }
    //Debug();
    // 1. 无解的情况:
    for (i = k; i < equ; ++i){
        if (a[i][col] != 0) return -1;
    }
    // 2. 无穷解的情况:
    if (k < var){
        
        int num = 0,freeidx=0;
        for (i = k - 1; i >= 0; --i){
            num = 0;
            int tmp = a[i][var];
            for (j = 0; j < var; ++j){
                if (a[i][j] != 0 && free_x[j]){
                    num++;
                    freeidx = j;
                }
            }
            if (num > 1) continue;
            tmp = a[i][var];
            for (j = 0; j < var; ++j){
                if (a[i][j] && j != freeidx) tmp -= a[i][j]*X[j];
            }
            //这里也要
            
            int k2 = (tmp%3+3)%3;
            int k1 = (a[i][freeidx]%3+3)%3;
            if(k1!=0)
            {
                X[freeidx] = k2*(int)GetNi(k1, 3);
            }
            else
            {
                X[freeidx] = 0;
                //printf("X[%d]为任意?\n",i);
            }
            
            //X[freeidx] = tmp/a[i][freeidx];
            free_x[freeidx] = 0;
        }
        return var - k;
    }
    // 3. 唯一解的情况:
    for (i = k - 1; i >= 0; --i){
        int tmp = a[i][var];
        for (j = i + 1; j < var; ++j){
            tmp -= a[i][j]*X[j];
        }
        //强行搞一发
        int k2 = (tmp%3+3)%3;
        int k1 = (a[i][i]%3+3)%3;
        if(k1!=0)
        {
            X[i] = k2*(int)GetNi(k1, 3);
        }
        else
        {
            X[i] = 0;
            //printf("X[%d]为任意?\n",i);
        }
        //X[i] = tmp/a[i][i];//不整除?
    }
    return 0;
}



int g[33][33];
int save[33][33][33];

int getni(int x)
{
    if(x==1) return 2;
    if(x==2) return 1;
    return 0;
}

void func(int x,int y)
{
    g[x][y] = (g[x][y]+2)%3;
    g[x+1][y] = (g[x+1][y]+1)%3;
    g[x][y+1] = (g[x][y+1]+1)%3;
    g[x-1][y] = (g[x-1][y]+1)%3;
    g[x][y-1] = (g[x][y-1]+1)%3;
}

int main() {
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&g[i][j]);
        memset(save,0,sizeof(save));
        
        for(int i=1;i<=m;i++)
        {
            save[1][i][i] = 1;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int k=0;k<=m;k++)
                {
                    int tmp = (save[i-1][j][k]*2+save[i-1][j+1][k]+save[i-1][j-1][k]) + save[i-2][j][k];
                    if(k == 0) tmp += g[i-1][j];
                    tmp %= 3;
                    save[i][j][k] = getni(tmp);
                }
            }
        }
        
        //然后构建矩阵
        memset(a,0,sizeof(a));
        equ = m;
        var = m;
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k<=m;k++)
            {
                int tmp = save[n][j][k]*2+save[n][j+1][k]+save[n][j-1][k] + save[n-1][j][k];
                if(k==0)
                {
                    tmp += g[n][j];
                    a[j-1][m] = getni(tmp%3);
                }
                else a[j-1][k-1] = tmp%3;
            }
        }
        CL(X,0);
        CL(free_x,0);
        int free_num = Guass();
        if(free_num == -1 || free_num == -2){ cout<<free_num<<" 错误"<<endl; continue;}
        int ans = 0;
        int saveans[33][33];
        memset(saveans,0,sizeof(saveans));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                int tmp = 0;
                for(int k=0;k<=m;k++)
                {
                    if(k==0) tmp += save[i][j][0];
                    else tmp += save[i][j][k]*X[k-1];
                    tmp %= 3;
                }
                ans += tmp;
                saveans[i][j] = tmp;
            }
        
        printf("%d\n",ans);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                for(int k=0;k<saveans[i][j];k++)
                {
                    printf("%d %d\n",i,j);
                    //func(i,j);
                }
            }
        
//        for(int i=1;i<=n;i++)
//        {
//            for(int j=1;j<=m;j++) printf("%d ",g[i][j]);
//            printf("\n");
//        }
    }
    return 0;
}
/*
 10
 1 3
 0 0 1
 3 3
 0 0 0
 0 0 0
 0 0 1
 1 2
 0 0
 2 30
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 */

 

posted @ 2016-08-04 01:13  chenhuan001  阅读(1433)  评论(0编辑  收藏  举报