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;
}