HDU--5755(高斯消元)

2016-07-27 14:23:49

【传送门】

题意:给出 N*M 的矩阵,每个元素为 0 或 1 或 2,每次操作可以选择一个元素给他加2,且其上下左右的格子里的数加1,所有操作都在模3域内操作。

     问一个可行的操作方案,使得方案总数不超过 2 * N * M 。 1 <= N , M <= 30

思路:这题虽然可以暴力建出 900 * 900 的矩阵进行 900^3 的高斯消元,也能过。但是有更好的方法。

     首先设第一行每列的元素被操作多少次,设为 x1,x2 ... xm ,这样一来,第二行每列元素的操作次数也能确定,可以用 x1~xm 去表示,以此类推,第三行、第四行 ... 第 N 行 所有元素的操作次数都能被确定。

   我们发现第 i + 1 行操作完后,第 i 行就能全部变为 0,且不受后面的操作影响。唯一不能保证全零的是第 N 行,所以第 N 行的 M 个元素都要为 0,我们已经知道了他们的操作次数(用 x1~xn表示)。

        所以我们可以建立 M 条方程,每个方程 M 个变量进行高斯消元,解出解后代回去得到每个元素应该被操作的次数(一定 <= 2)。复杂度 O(M^3)

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include <set>
  8 #include 
  9 #include 
 10 #include 
 11 #include <string>
 12 #include 
 13 #include 
 14 using namespace std;
 15 
 16 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 17 #define MP(a,b) make_pair(a,b)
 18 #define PB(a) push_back(a)
 19 
 20 typedef long long ll;
 21 typedef unsigned int ui;
 22 typedef pair<int,int> pii;
 23 const double eps = 1e-8;
 24 const int INF = (1 << 30) - 1;
 25 const int MAXN = 910;
 26 
 27 int T,N,M,top;
 28 int A[50][50][50],B[50][50][50],G[50][50],tg[50][50];
 29 int g[50][50],x[50],X[3000],Y[3000];
 30 int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
 31 
 32 void Gauss(){
 33     for(int i = 1,col = 1; col <= M && i <= M; ++i,++col){
 34         int r = -1;
 35         for(int j = i; j <= M; ++j) if(g[j][col]){
 36             r = j;
 37             break;
 38         }
 39         if(r == -1){
 40             --i;
 41             continue;
 42         }
 43         if(r != i) for(int j = col; j <= M + 1; ++j) swap(g[i][j],g[r][j]);
 44         for(int k = i + 1; k <= M; ++k){
 45             if(g[k][i]){
 46                 int tmp = (g[k][i] == g[i][i]) ? 1 : 2;
 47                 for(int j = col; j <= M + 1; ++j){
 48                     g[k][j] = ((g[k][j] - tmp * g[i][j]) % 3 + 3) % 3;
 49                 }
 50             }
 51         }
 52     }
 53     int pos;
 54     for(int i = M; i >= 1; --i){
 55         for(pos = 1; g[i][pos] == 0 && pos <= M; ++pos);
 56         if(pos > M) continue;
 57         for(int j = pos + 1; j <= M; ++j){
 58             g[i][M + 1] = ((g[i][M + 1] - g[i][j] * x[j]) % 3 + 3) % 3;
 59         }
 60         x[pos] = g[i][M + 1];
 61         if(g[i][pos] == 2) x[pos] ^= 3;
 62     }
 63 }
 64 
 65 int main(){
 66     scanf("%d",&T);
 67     while(T--){
 68         scanf("%d%d",&N,&M);
 69         top = N * M;
 70         for(int i = 1; i <= N; ++i)
 71             for(int j = 1; j <= M; ++j)
 72                 scanf("%d",&G[i][j]);
 73         memset(A,0,sizeof(A));
 74         memset(B,0,sizeof(B));
 75         memset(g,0,sizeof(g));
 76         memset(x,0,sizeof(x));
 77         for(int j = 1; j <= M; ++j){
 78             B[1][j][j] = 1;
 79             if(j - 1 >= 1) A[1][j][j - 1] = 1;
 80             A[1][j][j] = 2;
 81             if(j + 1 <= M) A[1][j][j + 1] = 1;
 82             A[1][j][M + 1] = G[1][j];
 83         }
 84         for(int i = 2; i <= N; ++i){
 85             for(int j = 1; j <= M; ++j)
 86                 for(int k = 1; k <= M + 1; ++k)
 87                     B[i][j][k] = ((3 - A[i - 1][j][k]) % 3 + 3) % 3;
 88             for(int j = 1; j <= M; ++j){
 89                 A[i][j][M + 1] = G[i][j];
 90                 for(int k = 1; k <= M + 1; ++k){
 91                     A[i][j][k] = ((A[i][j][k] + 
 92                         B[i - 1][j][k] + 2 * B[i][j][k] + B[i][j - 1][k] + B[i][j + 1][k]) % 3 + 3) % 3;
 93                 }
 94             }
 95         }
 96         for(int i = 1; i <= M; ++i){
 97             for(int j = 1; j <= M + 1; ++j){
 98                 g[i][j] = A[N][i][j];
 99             }
100             g[i][M + 1] = ((3 - g[i][M + 1]) % 3 + 3) % 3;
101         }
102         Gauss();
103         int cnt = 0;
104         for(int i = 1; i <= N; ++i){
105             for(int j = 1; j <= M; ++j){
106                 int ans = B[i][j][M + 1];
107                 for(int k = 1; k <= M; ++k){
108                     ans = ((ans + B[i][j][k] * x[k]) % 3 + 3) % 3;
109                 }
110                 while(ans--){
111                     X[++cnt] = i;
112                     Y[cnt] = j;
113                 }
114             }
115         }
116         printf("%d\n",cnt);
117         for(int i = 1; i <= cnt; ++i) printf("%d %d\n",X[i],Y[i]);
118     }
119     return 0;
120 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/5711133.html

你可能感兴趣的:(ui)