codevs 2495 水叮当的舞步

Description

  水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
  水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
  由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。
  

解题报告

IDA弄一下,需要相当的卡常技巧
首先IDA
设计的是不同的颜色数量,容易发现这是最好的情况.
那么讲一下实现:
我们拿\((1,1)\)位置扩展,扩展到的标记一下,然后枚举\([0,5]\)修改,进入下一层dfs。这样可以拿到50分了,考虑优化,用bfs标记,把走到的加入队列中,每一次修改队列中的元素,这样就不需要枚举所有的位置了,另外vis数组可以考虑不清空,滚动标记即可,这样就可以70分了.\((1.5s)\)
好的,到这里这个算法我就做不下去了.....需要发挥你们的智慧继续卡常
正解是差不多的,但是搜索状态很巧妙
分析这个过程,发现其实是一个从\((1,1)\)开始扩展范围的过程,所以转移只需要一个 \(vis\) 数组即可,是1表示已经被 \((1,1)\) 覆盖,2表示没有被覆盖,每一次选择一个颜色,然后把没有扩展到为该颜色的点 \(vis\) 标记为2,这样复杂度优秀在不需要每一次从 \((1,1)\) 开始扩展了

70分

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=9,mod=1e8;
int n,li=0,q[83][2],b[N][N],a[N][N],sum,vs=0;bool flag;
int mx[4]={0,0,1,-1},my[4]={1,-1,0,0};
il void getblock(){
   vs++;if(vs>=mod)vs=0;b[1][1]=vs;
   RG int x,y,tx,ty,i;int t=0;sum=1;
   q[1][0]=1;q[1][1]=1;
   while(t!=sum){
      x=q[++t][0];y=q[t][1];
      for(i=0;i<4;i++){
         tx=mx[i]+x;ty=my[i]+y;
         if(tx>n || tx<1 || ty>n || ty<1)continue;
         if(a[tx][ty]!=a[1][1] || b[tx][ty]==vs)continue;
         q[++sum][0]=tx;q[sum][1]=ty;b[tx][ty]=vs;
      }
   }
}
bool co[6];
il int getkind(){
   RG int i,j;
   for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
         if(b[i][j]!=vs)co[a[i][j]]=true;
   int ret=0;
   for(i=0;i<=5;i++)ret+=co[i],co[i]=0;
   return ret;
}
il int Pienough(int dep){
   getblock();int x=getkind();
   if(x==0)flag=true;
   return x+dep<=li;
}
il void dfs(int dep){
   if(dep>=li)return ;
   if(flag)return ;
   getblock();
   int now[83][2],last=a[1][1],si=sum;
   RG int j;
   memcpy(now,q,sizeof(q));
   for(int i=0;i<=5;i++){
      if(last==i)continue;
      for(j=1;j<=si;j++)
         a[now[j][0]][now[j][1]]=i;
      if(Pienough(dep+1))dfs(dep+1);
      for(j=1;j<=si;j++)
         a[now[j][0]][now[j][1]]=last;
      if(flag)return ;
   }
}
void work()
{
   memset(a,0,sizeof(a));vs=0;
   for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
         scanf("%d",&a[i][j]);
   flag=false;
   getblock();if(getkind()==0){puts("0");return ;}
   for(li=0;;li++){
      dfs(0);
      if(flag){
         printf("%d\n",li);
         return ;
      }
   }
}

int main()
{
	while(~scanf("%d",&n) && n)work();
	return 0;
}

优美的100写法

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=9;
int a[N][N],vis[N][N],n,li;bool flag;
int mx[4]={1,-1,0,0},my[4]={0,0,1,-1};
void getblock(int x,int y,int col){
    vis[x][y]=1;
    int tx,ty;
    for(int i=0;i<4;i++){
        tx=x+mx[i];ty=y+my[i];
        if(tx>n || tx<1 || ty>n || ty<1)continue;
        if(vis[tx][ty]==1)continue;
        vis[tx][ty]=2;
        if(a[tx][ty]==col)getblock(tx,ty,col);
    }
}
bool co[N];
int Pienough(){
    int ret=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(vis[i][j]!=1)co[a[i][j]]=true;
    for(int i=0;i<=5;i++)ret+=co[i],co[i]=0;
    return ret;
}
bool Pi(int x){
    int ret=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(vis[i][j]==2 && a[i][j]==x){
                ret++;
                getblock(i,j,x);
            }
        }
    return ret;
}
void dfs(int dep){
    int x=Pienough(),b[N][N];
    if(x==0){flag=true;return ;}
    if(x+dep>li)return ;
    for(int i=0;i<=5;i++){
        memcpy(b,vis,sizeof(b));
        if(Pi(i))dfs(dep+1);
        memcpy(vis,b,sizeof(vis));
    }
}
void work()
{
    memset(vis,0,sizeof(vis));flag=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    getblock(1,1,a[1][1]);
    for(li=0;;li++){
        dfs(0);
        if(flag)break;
    }
    printf("%d\n",li);
}

int main()
{
	while(~scanf("%d",&n) && n)work();
	return 0;
}

posted @ 2017-10-12 14:20  PIPIBoss  阅读(262)  评论(0编辑  收藏  举报