棋盘染色2

【题目描述】

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

【输入描述】

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

【输出描述】

输出一个整数,表示最少需要染色的格子数。

【样例输入】

5
11100
11000
10000
01111
11111

【样例输出】

1

 

70分迭代搜索(原谅我蒟蒻):

源代码:

#include<cstdio>
#include<cstring>
int x[4]={0,0,1,-1},y[4]={1,-1,0,0};
int n,t1,t2,Num,Total;
bool f[105][6],Vis[105][6];
void Check(int X,int Y) //遍历全图,统计染色点数。
{
    Num++;
    Vis[X][Y]=true;
    for(int a=0;a<4;a++)
    {
        int T1=X+x[a];
        int T2=Y+y[a]; //精髓,有的点只有被染色成连通块才会被统计到。
        if (!Vis[T1][T2]&&T1>=1&&T1<=n&&T2>=1&&T2<=5&&f[T1][T2]) 
          Check(T1,T2);
    }
}
bool Can(int t) //判断是否合法。
{
    Num=0; //经过Check()后全图总共有Num个点被染色。
    memset(Vis,false,sizeof(Vis));
    Check(t1,t2); //从最后搜索,挺方便。
    if (Num==Total+t)
      return true; //Total为初始时染色点数,t为DFS()之后多染的点数。
    return false;
}
bool DFS(int X,int Y,int Now,int Sum) //迭代搜索,X、Y为坐标,Now表示当前比初始状态多涂了Now个点,Sum表示目标是涂Sum个点。
{
    if (Now==Sum) //到达极限。
    {
        if (Can(Sum))
          return true; //判断是否已连通。
        return false;
    }
    for (int a=Y+1;a<=5;a++) //搜索并连接节点的该行的右边。
      if (!f[X][a])
      {
            f[X][a]=true;
            if (DFS(X,a,Now+1,Sum))
              return true;
            f[X][a]=false;
      }
    for (int a=X+1;a<=n;a++) //同理于上,搜索节点所在行的下方所有区域。
      for (int b=1;b<=5;b++)
        if (!f[a][b])
        {
            f[a][b]=true;
            if (DFS(a,b,Now+1,Sum))
              return true;
            f[a][b]=false;
        }
    return false; //依旧不成立。
}
int main()
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      for (int b=1;b<=5;b++)
      {
        scanf("%1d",&f[a][b]); //真是太神奇了,"%Xd"表示读入X位数,也可忽略空格。
        if (f[a][b])
        {
            Total++; //黑格总数。
            t1=a; //最后的黑格。
            t2=b;
        }
      }
    for (int a=0;a<=5*n-Total;a++) //迭代。
      if (DFS(1,1,0,a))
      {
        printf("%d",a);
        return 0;
      }
}

 

posted @ 2016-08-17 11:37  前前前世。  阅读(321)  评论(0编辑  收藏  举报