Poj 1753 Flip Game Gauss消元

34226 ワード

タイトル接続:
   http://poj.org/problem?id=1753
テーマ:
1つの4*4の格子があって、それぞれの格子は黒あるいは白色で、その中の1つの格子を反転してそれを変色させて、その上下左右の格子を牽引して同時に変色して、最終的に少なくともいくつの格子を反転してやっと4*4の格子を同じ色に変えることができますか?
問題解決の考え方:
実はこのテーマはどのようにしてすべてすることができて、暴捜することができて、位の演算、dfs、最近ガウスの消元を学んで、ガウスで解いて、16個の格子の広がりの行列は16*17で、階段の行列を求めた後に、列挙して不確定な変元を挙げて、不確定な変元と階段の行列によって確定な変元を求めて、それから操作する回数を統計して、最も良いことを選択します.
  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 using namespace std;
  7 
  8 const int maxn = 20;
  9 int det[maxn][maxn], equ, var;
 10 
 11 int gauss ()
 12 {
 13     int max_i, k, col, cou = 0;
 14     int free_num[maxn], free_i[maxn], x[maxn];
 15 
 16     memset (free_i, 0, sizeof(free_i));
 17     memset (x, 0, sizeof(x));
 18 
 19     for (k=col=0; k<equ&&col<var; k++, col++)
 20     {//       
 21         max_i = k;
 22         for (int i=k+1; i<equ; i++)//    col             k   .
 23             if (det[max_i][col] < det[i][col])
 24                 max_i = i;
 25         if (det[max_i][col] == 0)
 26         {//    col  k     0 ,          .
 27             free_i[col] = 1;
 28             x[cou++] = col;
 29             k --;
 30             continue;
 31         }
 32         if (max_i != k)
 33             for (int i=col; i<=var; i++)
 34                 swap(det[max_i][i], det[k][i]);
 35         for (int i=k+1; i<equ; i++)
 36             if (det[i][col])//        .
 37                 for (int j=col; j<=var; j++)
 38                     det[i][j] ^= det[k][j];
 39     }
 40     for (int i=k; i<equ; i++)
 41         if (det[i][var])//      
 42             return maxn;
 43     int res = maxn, num = 1<<cou;
 44     for (int i=0; i<num; i++)
 45     {
 46         int nu = 0, m = i;
 47         memset (free_num, 0, sizeof(free_num));
 48         for (int j=0; j<cou; j++)
 49         {//       
 50             if (m % 2)
 51             {
 52                 free_num[x[j]] = 1;
 53                 nu ++;
 54             }
 55             m /= 2;
 56         }
 57         for (int j=k-1; j>=0; j--)
 58             if (!free_i[j])
 59             {//
 60                 int temp = det[j][16];
 61                 for (int l=j+1; l<var; l++)
 62                     if (det[j][l])
 63                         temp ^= free_num[l];
 64                 free_num[j] = temp;
 65                 if (temp)
 66                     nu ++;
 67             }
 68         res = min (res, nu);
 69     }
 70     return res;
 71 }
 72 int main ()
 73 {
 74     int map[maxn], j = 0;
 75     char str[maxn];
 76 
 77     equ = var = 16;
 78     for (int i=0; i<4; i++)
 79     {
 80         scanf ("%s", str);
 81         for (int l=0; str[l]; l++)
 82             if (str[l] == 'b')
 83                 map[j++]=1;
 84             else
 85                 map[j++] = 0;
 86     }
 87 
 88     memset (det, 0, sizeof(det));
 89     for (int i=0; i<16; i++)
 90     {//          
 91         det[i][i] = 1;
 92         det[i][16] = map[i];
 93         if (i < 12)
 94             det[i][i+4] = 1;
 95         if (i > 3)
 96             det[i][i-4] = 1;
 97         if (i % 4 != 0)
 98             det[i][i-1] = 1;
 99         if (i % 4 != 3)
100             det[i][i+1] = 1;
101     }
102     int res = gauss ();
103     memset (det, 0, sizeof(det));
104     for (int i=0; i<16; i++)
105     {
106         det[i][i] = 1;
107         det[i][16] = 1 - map[i];
108         if (i < 12)
109             det[i][i+4] = 1;
110         if (i > 3)
111             det[i][i-4] = 1;
112         if (i % 4 != 0)
113             det[i][i-1] = 1;
114         if (i % 4 != 3)
115             det[i][i+1] = 1;
116     }
117     res = min (res, gauss());
118     if (res == maxn)
119         printf ("Impossible
"); 120 else 121 printf ("%d
", res); 122 return 0; 123 }

ついでにもう一つの暴捜コードを貼って、簡単で乱暴で、はっきりしています
  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 
  7 #define N 5
  8 #define INF 0x3f3f3f
  9 using namespace std;
 10 
 11 char a[N][N], map[N][N];
 12 int dir[][2] = {0,0, 1,0, 0,1, -1,0, 0,-1};
 13 
 14 int change(char ch, int num);
 15 void turn (int x, int y, char X[][N]);
 16 void init ();
 17 
 18 int main ()
 19 {
 20     int i, j, min, sum, num;
 21 
 22     for (i=0; i<4; i++)
 23        {
 24             scanf ("%s", a[i]);
 25             strcpy (map[i], a[i]);
 26        }
 27 
 28     min = INF;
 29 
 30     for (i=0; i<16; i++)
 31     {
 32         sum = i;
 33         num = 0;
 34         for (j=0; j<4; j++)
 35         {
 36             if ( sum % 2 )
 37                 {
 38                     turn(0, j, map);
 39                     num ++;
 40                 }
 41             sum /= 2;
 42         }
 43 
 44         init();
 45         sum = change ('b', num);
 46         if (min > sum)
 47             min = sum;
 48         init();
 49         sum = change ('w', num);
 50         if (min > sum)
 51             min = sum;
 52 
 53         sum = i;
 54         for (j=0; j<4; j++)
 55         {
 56             if ( sum % 2 )
 57             {
 58                turn (0, j, map);
 59             }
 60             sum /= 2;
 61         }
 62     }
 63     if (min == INF)
 64         printf ("Impossible
"); 65 else 66 printf ("%d
", min); 67 return 0; 68 } 69 int change( char ch, int num) 70 { 71 int i, j; 72 73 for (i=1; i<4; i++) 74 for (j=0; j<4; j++) 75 if (a[i-1][j] != ch) 76 { 77 num ++; 78 turn(i, j, a); 79 } 80 for (i=0; i<4; i++) 81 if (a[3][i] != ch) 82 return INF; 83 return num; 84 } 85 86 void turn (int x, int y, char X[][N]) 87 { 88 for (int i=0; i<5; i++) 89 { 90 int A = x + dir[i][0]; 91 int B = y + dir[i][1]; 92 93 if (A >= 0 && A < 4 && B >= 0 && B < 4) 94 { 95 if (X[A][B] == 'w') 96 X[A][B] = 'b'; 97 else 98 X[A][B] = 'w'; 99 } 100 } 101 } 102 103 void init () 104 { 105 int i; 106 for (i=0; i<4; i++) 107 strcpy (a[i], map[i]); 108 }