zoukankan      html  css  js  c++  java
  • POJ 1681 Painter's Problem (高斯消元 枚举自由变元求最小的步数)

    题目链接

    题意:

    一个n*n 的木板 ,每个格子 都 可以 染成 白色和黄色,( 一旦我们对也个格子染色 ,他的上下左右 都将改变颜色);

    给定一个初始状态 , 求将 所有的 格子 染成黄色 最少需要染几次?  若 不能 染成 输出 inf。

    分析:

    和1222差不多,唯一的区别是这个题还要求 最短的步数,其实只需要枚举一下最后的x[][]是否为1,即是否需要按下,

    由于只有无解或者解唯一,因为按的顺序是没有影响的,所以只要是有解一定唯一,而且最短的情况是每个格子只按一次,

    因为按两次以后就变为原来的状态了。

    这个是最严谨的这个题的AC代码,因为我做1753的时候用原来的方法错了,看了Kuangbin的博客,知道原来的方法不对,貌似只有一个解和无解的时候才会对。

    但是这个是对的:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <cmath>
      6 #include <algorithm>
      7 #define LL __int64
      8 const int maxn = 300+10;
      9 const int INF = 1<<28;
     10 using namespace std;
     11 int equ, var, fn;
     12 int a[maxn][maxn], x[maxn];
     13 int free_x[maxn];
     14 int gcd(int a, int b)
     15 {
     16     return b==0?a:gcd(b, a%b);
     17 }
     18 int lcm(int a, int b)
     19 {
     20     return a*b/gcd(a, b);
     21 }
     22 int Gauss()
     23 {
     24     int x_mo;
     25     x_mo = 2;
     26     int i, j, k, max_r, col;
     27     int ta, tb, LCM, fx_num = 0;
     28     col = 0;
     29 
     30     for(k = 0; k<equ && col<var; k++, col++)
     31     {
     32         max_r = k;
     33         for(i = k+1; i < equ; i++)
     34             if(abs(a[i][col])>abs(a[max_r][col]))
     35             max_r = i;
     36 
     37         if(max_r != k)
     38             for(j = k; j < var+1; j++)
     39             swap(a[k][j], a[max_r][j]);
     40 
     41         if(a[k][col]==0)
     42         {
     43             free_x[fx_num++] = col; //求自由变元所在的列
     44             k--;
     45             continue;
     46         }
     47         for(i = k+1; i < equ; i++)
     48         {
     49             if(a[i][col] != 0)
     50             {
     51                 LCM = lcm(abs(a[i][col]), abs(a[k][col]));
     52                 ta = LCM/abs(a[i][col]);
     53                 tb= LCM/abs(a[k][col]);
     54                 if(a[i][col]*a[k][col] < 0) tb = -tb;
     55 
     56                 for(j = col; j < var+1; j++)
     57                 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo;
     58             }
     59         }
     60     }
     61     for(i = k; i < equ; i++)
     62     if(a[i][col] != 0)
     63     return -1;
     64     
     65     //以下为模2情况下的,枚举变元的方法。
     66     int stat=1<<(var-k);//自由变元有 var-k 个
     67     int res=INF;
     68     for(i=0;i<stat;i++)//枚举所有变元
     69     {
     70         int cnt=0;
     71         int index=i;
     72         for(j=0;j<var-k;j++)
     73         {
     74             x[free_x[j]]=(index&1);
     75             if(x[free_x[j]]) cnt++;
     76             index>>=1;
     77         }
     78         for(j=k-1;j>=0;j--)
     79         {
     80             int tmp=a[j][var];
     81             for(int l=j+1;l<var;l++)
     82               if(a[j][l]) tmp^=x[l];
     83             x[j]=tmp;
     84             if(x[j])cnt++;
     85         }
     86         if(cnt<res)res=cnt;
     87     }
     88     return res;
     89 }
     90 
     91 int main()
     92 {
     93     int t, i, j, n, tmp;
     94     char s[maxn];
     95     scanf("%d", &t);
     96     while(t--)
     97     {
     98         memset(a, 0, sizeof(a));
     99         memset(x, 0, sizeof(x));
    100         scanf("%d", &n);
    101         equ = n*n;
    102         var = n*n;
    103         for(i = 0; i < n; i++)
    104         {
    105             getchar();
    106             scanf("%s", s);
    107             for(j = 0; j < n; j++)
    108             {
    109                 if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0
    110                 else a[i*n+j][n*n] = 1;
    111             }
    112         }
    113         for(i = 0; i < n; i++)
    114         for(j = 0; j < n; j++)
    115         {
    116             tmp = i*n+j;
    117             a[tmp][tmp] = 1;
    118             if(j<=n-2)
    119             a[tmp+1][tmp] = 1;
    120             if(j>=1)
    121             a[tmp-1][tmp] = 1;
    122             if(tmp+n<n*n)
    123             a[tmp+n][tmp] = 1;
    124             if(tmp-n>=0)
    125             a[tmp-n][tmp] = 1;
    126         }
    127         fn = Gauss();
    128         if(fn==-1)
    129         printf("inf
    ");
    130         else
    131         printf("%d
    ", fn);
    132     }
    133     return 0;
    134 }

    这个AC代码是我按照模板改的,但是在多解的情况下不对:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <cmath>
      6 #include <algorithm>
      7 #define LL __int64
      8 const int maxn = 300+10;
      9 using namespace std;
     10 int equ, var, fn;
     11 int a[maxn][maxn], x[maxn];
     12 int gcd(int a, int b)
     13 {
     14     return b==0?a:gcd(b, a%b);
     15 }
     16 int lcm(int a, int b)
     17 {
     18     return a*b/gcd(a, b);
     19 }
     20 int Gauss()
     21 {
     22     int x_mo;
     23     x_mo = 2;
     24     int i, j, k, max_r, col;
     25     int ta, tb, LCM, tmp;
     26     col = 0;
     27 
     28     for(k = 0; k<equ && col<var; k++, col++)
     29     {
     30         max_r = k;
     31         for(i = k+1; i < equ; i++)
     32             if(abs(a[i][col])>abs(a[max_r][col]))
     33             max_r = i;
     34 
     35         if(max_r != k)
     36             for(j = k; j < var+1; j++)
     37             swap(a[k][j], a[max_r][j]);
     38 
     39         if(a[k][col]==0)
     40         {
     41             k--;
     42             continue;
     43         }
     44         for(i = k+1; i < equ; i++)
     45         {
     46             if(a[i][col] != 0)
     47             {
     48                 LCM = lcm(abs(a[i][col]), abs(a[k][col]));
     49                 ta = LCM/abs(a[i][col]);
     50                 tb= LCM/abs(a[k][col]);
     51                 if(a[i][col]*a[k][col] < 0) tb = -tb;
     52 
     53                 for(j = col; j < var+1; j++)
     54                 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo;
     55             }
     56         }
     57     }
     58     for(i = k; i < equ; i++)
     59     if(a[i][col] != 0)
     60     return -1;
     61 
     62     for(i = var-1; i >= 0; i--)
     63     {
     64         tmp = a[i][var];
     65         for(j = i+1; j < var; j++)
     66         if(a[i][j] != 0)
     67         tmp = ((tmp-a[i][j]*x[j])%x_mo+x_mo)%x_mo;
     68         if(a[i][i]==0)  //注意这a[i][i]可能为0, 我改为这样就对了。
     69         x[i] = 0;
     70         else
     71         {
     72             while(tmp%a[i][i]!=0) tmp += x_mo;
     73             x[i] = (tmp/a[i][i])%x_mo;
     74         }
     75     }
     76     return 0;
     77 }
     78 
     79 int main()
     80 {
     81     int t, i, j, n, ans, tmp;
     82     char s[maxn];
     83     scanf("%d", &t);
     84     while(t--)
     85     {
     86         memset(a, 0, sizeof(a));
     87         memset(x, 0, sizeof(x));
     88         scanf("%d", &n);
     89         equ = n*n;
     90         var = n*n;
     91         for(i = 0; i < n; i++)
     92         {
     93             getchar();
     94             scanf("%s", s);
     95             for(j = 0; j < n; j++)
     96             {
     97                 if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0
     98                 else a[i*n+j][n*n] = 1;
     99             }
    100         }
    101         for(i = 0; i < n; i++)
    102         for(j = 0; j < n; j++)
    103         {
    104             tmp = i*n+j;
    105             a[tmp][tmp] = 1;
    106             if(j<=n-2)
    107             a[tmp+1][tmp] = 1;
    108             if(j>=1)
    109             a[tmp-1][tmp] = 1;
    110             if(tmp+n<n*n)
    111             a[tmp+n][tmp] = 1;
    112             if(tmp-n>=0)
    113             a[tmp-n][tmp] = 1;
    114         }
    115         fn = Gauss();
    116         if(fn==-1)
    117         printf("inf
    ");
    118         else
    119         {
    120             ans = 0;
    121             for(i = 0; i < n*n; i++)
    122             if(x[i]==1)  //枚举解为1,就是需要将原来的翻转的。
    123             ans ++;
    124             printf("%d
    ", ans);
    125         }
    126     }
    127     return 0;
    128 }

    这个AC代码的模板用的是别人的对二取模的模板,用的是 ^异或,不会出现除0的情况。在多解的情况下也不对。。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <cmath>
      6 #include <algorithm>
      7 #define LL __int64
      8 const int maxn = 300+10;
      9 using namespace std;
     10 int equ, var, fn;
     11 int a[maxn][maxn], x[maxn];
     12 int gcd(int a, int b)
     13 {
     14     return b==0?a:gcd(b, a%b);
     15 }
     16 int lcm(int a, int b)
     17 {
     18     return a*b/gcd(a, b);
     19 }
     20 int  Gauss()
     21 {
     22     int i,j,k;
     23     int max_r;
     24     int col;
     25     int temp;
     26 
     27     int free_x_num;
     28     int free_index;
     29 
     30     col=0;
     31     for(k=0;k<equ&&col<var;k++,col++)
     32     {
     33         max_r=k;
     34         for(i=k+1;i<equ;i++)
     35         {
     36             if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
     37         }
     38         if(max_r!=k)
     39         {
     40             for(j=col;j<var+1;j++)swap(a[k][j],a[max_r][j]);
     41         }
     42         if(a[k][col]==0)
     43         {
     44             k--;
     45             continue;
     46         }
     47         for(i=k+1;i<equ;i++)
     48         {
     49             if(a[i][col]!=0)
     50             {
     51                 for(j=col;j<var+1;j++)
     52                   a[i][j]^=a[k][j];
     53             }
     54         }
     55     }
     56     for(i=k;i<equ;i++)
     57     {
     58         if(a[i][col]!=0)return -1;
     59     }
     60     for(i=var-1;i>=0;i--)
     61     {
     62         x[i]=a[i][var];
     63         for(j=i+1;j<var;j++)
     64           x[i]^=(a[i][j]&&x[j]);
     65     }
     66     return 0;
     67 }
     68 
     69 int main()
     70 {
     71     int t, i, j, n, ans, tmp;
     72     char s[maxn];
     73     scanf("%d", &t);
     74     while(t--)
     75     {
     76         memset(a, 0, sizeof(a));
     77         memset(x, 0, sizeof(x));
     78         scanf("%d", &n);
     79         equ = n*n;
     80         var = n*n;
     81         for(i = 0; i < n; i++)
     82         {
     83             getchar();
     84             scanf("%s", s);
     85             for(j = 0; j < n; j++)
     86             {
     87                 if(s[j]=='y') a[i*n+j][n*n] = 0;
     88                 else a[i*n+j][n*n] = 1;
     89             }
     90         }
     91         for(i = 0; i < n; i++)
     92         for(j = 0; j < n; j++)
     93         {
     94             tmp = i*n+j;
     95             a[tmp][tmp] = 1;
     96             if(j<=n-2)
     97             a[tmp+1][tmp] = 1;
     98             if(j>=1)
     99             a[tmp-1][tmp] = 1;
    100             if(tmp+n<n*n)
    101             a[tmp+n][tmp] = 1;
    102             if(tmp-n>=0)
    103             a[tmp-n][tmp] = 1;
    104         }
    105         fn = Gauss();
    106         if(fn==-1)
    107         printf("inf
    ");
    108         else
    109         {
    110             ans = 0;
    111             for(i = 0; i < n*n; i++)
    112             if(x[i]==1)
    113             ans ++;
    114             printf("%d
    ", ans);
    115         }
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    转:关于JAVA多线程同步
    转:Java HashMap实现详解
    索引创建规则:
    数据库为什么要分库分表
    [设计模式] javascript 之 桥接模式
    [百度地图] ZMap 与 MultiZMap 封装类说明;
    [设计模式] Javascript 之 外观模式
    [设计模式] javascript 之 代理模式
    [设计模式] javascript 之 装饰者模式
    [设计模式] javascript 之 适配器模式
  • 原文地址:https://www.cnblogs.com/bfshm/p/3919949.html
Copyright © 2011-2022 走看看