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 <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <time.h> 11 #include <string> 12 #include <iostream> 13 #include <algorithm> 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 }