【HDU 5755】Gambler Bo(高斯消元)

【HDU 5755】Gambler Bo(高斯消元)

Gambler Bo

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 236    Accepted Submission(s): 91
Special Judge

Problem Description
Gambler Bo is very proficient in a matrix game.

You have a N×M matrix, every cell has a value in {0,1,2} .

In this game, you can choose a cell in the matrix, plus 2 to this cell, and plus 1 to all the adjacent cells.

for example, you choose the cell (x,y) , the value of (x,y) will be plused 2, and the value of (x1,y)(x+1,y)(x,y1)(x,y+1) will be plused 1.

if you choose the cell (1,2) , the cell (1,2) will be plused 2, and the cell (2,2)(1,1)(1,3) will be plused 1, the cell (0,2) won’t be changed because it’s out of the matrix.

If the values of some cells is exceed 2, then these values will be modulo 3.

Gambler Bo gives you such a matrix, your task is making all value of this matrix to 0 by doing above operations no more than 2NM times.

Input
First line, an integer T . There are T test cases.

In each test, first line is two integers N,M , and following N lines describe the matrix of this test case.

T10,1N,M30 , the matrix is random and guarantee that there is at least one operation solution.

Output
For each test, first line contains an integer num (0num2NM) describing the operation times.

Following num lines, each line contains two integers x,y (1xN,1yM) describing the operation cell.

The answer may not be unique, you can output any one.

Sample Input
2
2 3
2 1 2
0 2 0
3 3
1 0 1
0 1 0
1 0 1

Sample Output
1
1 2
5
1 1
1 3
2 2
3 1
3 3

Source
2016 Multi-University Training Contest 3

题目大意:
一个 nm mod3 矩阵,元素由 {0,1,2}
每次可以选择一个元素,将其 ADD 2(mod3) ,将它上下左右四个相邻元素(如果存在) ADD 1(mod3)
要求最终使矩阵变为全0矩阵
输出操作次数和每次操作位置。
要求次数 2mn
保证输入数据有解

数据范围有点可怕,但是高消解同余模方程可做 O((nm)3)

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define Pr pair
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 3;
const double eps = 1e-8;
const int MAXN = 1000;

int a[MAXN][MAXN];
int x[MAXN];

int gcd(int a,int b)
{
    while(b)
    {
        int t = b;
        b = a%b;
        a = t;
    }
    return a;
}

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


int Gauss(int equ,int var)
{
    int max_r,col,k;

    for(k = 0, col = 0; k < equ && col < var; ++k,++col)
    {
        max_r = k;
        for(int i = k+1; i < equ; ++i)
            if(abs(a[i][col]) > abs(a[max_r][col]))
                max_r = i;
        if(a[max_r][col] == 0)
        {
            --k;
            continue;
        }
        if(max_r != k)
            for(int j = col; j < var+1; ++j)
                swap(a[k][j],a[max_r][j]);
        for(int i = k+1; i < equ; ++i)
        {
            if(a[i][col] != 0)
            {
                int LCM = lcm(abs(a[i][col]),abs(a[k][col]));
                int ta = LCM/abs(a[i][col]);
                int tb = LCM/abs(a[k][col]);
                if(a[i][col]*a[k][col] < 0) tb = -tb;
                for(int j = col; j < var+1; ++j)
                    a[i][j] = ((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod;
            }
        }
    }

    for(int i = var-1; i >= 0; --i)
    {
        if(!a[i][i]) continue;
        int temp = a[i][var];
        for(int j = i+1; j < var; ++j)
        {
            if(a[i][j] != 0)
            {
                temp -= a[i][j]*x[j];
                temp = (temp%mod+mod)%mod;
            }
        }
        x[i] = (temp*a[i][i])%mod;
    }
    return 0;
}

Pr out[2333];
int solve(int equ,int var,int n,int m)
{
    int t = Gauss(equ,var);
    int ans = 0;

    for(int i = 0; i < var; ++i)
    {
        while(x[i])
        {
            out[ans].first = i/m+1;
            out[ans++].second = (i%m)+1;
            x[i]--;
        }
    }

    return ans;
}

int dirx[] = { 0, 0, 1,-1};
int diry[] = { 1,-1, 0, 0};

void init(int n,int m)
{
    int pos;

    int xx,yy;
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < m; ++j)
        {
            pos = i*m+j;
            scanf("%d",&a[pos][n*m]);
            a[pos][n*m] = ((mod-a[pos][n*m])%mod+mod)%mod;

            for(int k = 0; k < 4; ++k)
            {
                xx = i+dirx[k];
                yy = j+diry[k];

                if(xx < 0 || xx >= n || yy < 0 || yy >= m) continue;
                a[pos][xx*m+yy] = 1;
            }
            a[pos][pos] = 2;
        }
    }
}

int main()
{
    //fread("in.in");
    //fwrite("");

    int t;

    scanf("%d",&t);
    int n,m;

    while(t--)
    {
        scanf("%d%d",&n,&m);
        init(n,m);

        int ans = solve(n*m,n*m,n,m);

        printf("%d\n",ans);
        for(int i = 0; i < ans; ++i)
            printf("%d %d\n",out[i].first,out[i].second);
    }

    return 0;
}

你可能感兴趣的:(HDOJ,高斯消元,ACM道路之数学的艺术)