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

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com