1050 棋盘染色 2

1050 棋盘染色 2

题目描述 Description

有一个5*N的棋盘,棋盘中的一些格子已经被染成了黑色,你的任务是对最少的格子染色,使得所有的黑色能连成一块。

输入描述 Input Description

第一行一个整数N(<=100),接下来N行每行一个长度为5的01串,1表示所在格子已经被染成了黑色,0表示所在格子没有被染色。

输出描述 Output Description

第一行一个整数N(<=100),接下来N行每行一个长度为5的01串,1表示所在格子已经被染成了黑色,0表示所在格子没有被染色。

样例输入 Sample Input

5
11100
11000
10000
01111
11111

样例输出 Sample Output

1

数据范围及提示 Data Size & Hint

N(<=100)

 

轮廓型DP,又名插头DP。

这道题用广度记忆化搜索和插头DP,逐个格子递推。

#include <iostream>

#include <cstring>

#define ref(i,x,y) for(int i=x;i<=y;i++)

#define get(t,k) (((t)>>(2*(5-(k))))%4)

#define aj (1<<2*(5-(y)))

using namespace std;

int n,h,t,judx,judy;

int a[101][6],f[102][6][1025];

struct qmem{int x,y,s;}q[500001];

void init(){h=t=0;memset(f,1,sizeof f);}

void push(int x,int y,int s,int v){

       if (f[x][y][s]<=v)return;

       if (s==0&&(x*5+y<=judx*5+judy)&&q[h].s>0)return;

       t++;q[t].x=x;q[t].y=y;q[t].s=s;f[x][y][s]=v;

}

int getp(int s){

       bool p[6];memset(p,0,sizeof p);

       ref(i,1,5)p[get(s,i)]=1;ref(i,1,5)if(!p[i])return i;

}

int ch(int s,int w2,int w1){

       ref(i,1,5)if((s>>2*(i-1))%4==w2)s+=(1<<2*(i-1))*(w1-w2);

       return s;

}

bool only(int s,int w,int o){

       if (w==0)return 0;

       bool b=0;

       ref(i,1,5)if(get(s,i)!=w&&get(s,i)>0)b=1;

       ref(i,o+1,5)if(get(s,i)==w)b=0;

       ref(i,1,o-1)if(get(s,i)==w)b=0;

       return b;

}

bool ok(int s){

       int jud=0;

       ref(i,1,5)if(get(s,i)!=jud&&get(s,i)>0){

              if(jud==0)jud=get(s,i);else return 0;}

       return 1;

}

int main()

{

       cin>>n;

       ref(i,1,n)

       {

              char s[6];cin>>s;

              ref(j,0,4)a[i][j+1]=s[j]-48;

       }

       ref(i,1,n)ref(j,1,5)if(a[i][j]){judx=i;judy=j;}

       init();push(1,1,0,0);

       while(h<t)

       {

              h++;

              if(q[h].x>n)continue;

              int x,y,s,ff,w1,w2,ts;

              x=q[h].x;y=q[h].y;s=q[h].s;ff=f[x][y][s];

              w1=get(s,y-1);w2=get(s,y);ts=s-aj*w2;

              bool judge=0;

              if ((only(s,w1,y-1)&&x==n)||only(s,w2,y)||a[x][y])judge=1;

              if (a[x][y])ff--;

              if(y<5)

              {

                     if (!judge)push(x,y+1,ts,ff);

                     if(w1==0&&w2==0)push(x,y+1,ts+aj*getp(s),ff+1);else

                     if(w1==0&&w2>0)push(x,y+1,s,ff+1);else

                     if(w1>0&&w2==0)push(x,y+1,ts+aj*w1,ff+1);else

                     push(x,y+1,ch(s,w2,w1),ff+1);

              }else{

                     if (!judge)push(x+1,1,ts,ff);

                     if(w1==0&&w2==0)push(x+1,1,ts+aj*getp(s),ff+1);else

                     if(w1==0&&w2>0)push(x+1,1,s,ff+1);else

                     if(w1>0&&w2==0)push(x+1,1,ts+aj*w1,ff+1);else

                     push(x+1,1,ch(s,w2,w1),ff+1);

              }

       }

       int ans=f[n+1][1][0];

       ref(i,1,1024)if(ok(i)&&ans>=f[n+1][1][i]){

              ans=min(ans,f[n+1][1][i]);

              //cout<<i<<" "<<ans<<endl;

       }

       cout<<ans;

}

 

posted @ 2016-09-24 21:23  [lemon]  阅读(142)  评论(0编辑  收藏  举报
……