POJ 1681 Painter's Problem(高斯消元+枚举自由变元)

http://poj.org/problem?id=1681

题意:
有一块只有黄白颜色的n*n的板子,每次刷一块格子时,上下左右都会改变颜色,求最少刷几次可以使得全部变成黄色。

 

思路:

这道题目也就是要处理自由变元,如果自由变元为0,那么刷法是唯一的,如果有多个自由变元,那么可以有多种刷法,需要枚举处理。

借鉴了kuangbin大神的高斯消元模板,写得真的是好。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,int> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn = 400 + 5;
 17 
 18 int n;
 19 int equ,var;  //equ个方程,var个变元
 20 int x[maxn]; //解集
 21 int a[maxn][maxn]; //矩阵
 22 int free_x[maxn];  //存储自由变元
 23 int free_num;      //自由变元的个数
 24 
 25 //返回值为-1表示无解,为0表示唯一解,否则返回自由变元个数
 26 int Gauss()
 27 {
 28     int max_r,col,k;
 29     free_num=0;
 30     for(k=0,col=0; k<equ && col<var; k++,col++)
 31     {
 32         max_r=k;
 33         for(int i=k+1;i<equ;i++)
 34         {
 35             if(abs(a[i][col])>abs(a[max_r][col]))
 36                 max_r=i;
 37         }
 38         if(a[max_r][col]==0)
 39         {
 40             k--;
 41             free_x[free_num++]=col;  //这个是自由变元;
 42             continue;
 43         }
 44         if(max_r!=k)
 45         {
 46             for(int j=col; j<var+1; j++)
 47                 swap(a[k][j],a[max_r][j]);
 48         }
 49         for(int i=k+1;i<equ;i++)
 50         {
 51             if(a[i][col]!=0)
 52             {
 53                 for(int j=col;j<var+1;j++)
 54                     a[i][j]^=a[k][j];
 55             }
 56         }
 57     }
 58     for(int i=k;i<equ;i++)
 59         if(a[i][col]!=0)  return -1;  //无解
 60     if(k<var)  return var-k;          //有多解时返回自由变元个数
 61     //唯一解,回代
 62     for(int i=var-1; i>=0 ;i--)
 63     {
 64         x[i]=a[i][var];
 65         for(int j=i+1; j<var; j++)
 66             x[i]^=(a[i][j] && x[j]);
 67     }
 68     return 0;
 69 }
 70 
 71 void print(int t)
 72 {
 73     if(t==-1)  puts("inf");
 74     else if(t==0)
 75     {
 76         int ans=0;
 77         for(int i=0;i<n*n;i++)   ans+=x[i];
 78         printf("%d\n",ans);
 79     }
 80     else
 81     {
 82         //枚举自由变元
 83         int ans=INF;
 84         for(int i=0;i<(1<<t);i++)
 85         {
 86             int cnt=0;
 87             for(int j=0;j<t;j++)
 88             {
 89                 if(i&(1<<j))
 90                 {
 91                     x[free_x[j]]=1;
 92                     cnt++;
 93                 }
 94                 else x[free_x[j]]=0;
 95             }
 96             for(int j=var-t-1;j>=0;j--)
 97             {
 98                 int idx;
 99                 for(idx=j; idx<var; idx++)
100                     if(a[j][idx])  break;
101                 x[idx]=a[j][var];
102                 for(int l=idx+1; l<var; l++)
103                     if(a[j][l])  x[idx]^=x[l];
104                 cnt+=x[idx];
105             }
106             ans=min(ans,cnt);
107         }
108         printf("%d\n",ans);
109     }
110 }
111 
112 int main()
113 {
114     //freopen("in.txt","r",stdin);
115     int T;
116     scanf("%d",&T);
117     while(T--)
118     {
119         scanf("%d",&n);
120         memset(a,0,sizeof(a));
121 
122         for(int i=0;i<n*n;i++)
123         {
124             a[i][i]=1;
125             if(i/n)      a[i-n][i]=1;
126             if(i/n<n-1)  a[i+n][i]=1;
127             if(i%n)      a[i-1][i]=1;
128             if(i%n<n-1)  a[i+1][i]=1;
129         }
130 
131         char s[20];
132         for(int i=0;i<n;i++)
133         {
134             scanf("%s",s);
135             for(int j=0;j<n;j++)
136             {
137                 if(s[j]=='y')  a[i*n+j][n*n]=0;
138                 else a[i*n+j][n*n]=1;
139             }
140         }
141 
142         memset(x,0,sizeof(x));
143         equ=var=n*n;
144         print(Gauss());
145     }
146     return 0;
147 }
posted @ 2017-08-03 09:23  Kayden_Cheung  阅读(240)  评论(0编辑  收藏  举报
//目录