codevs 2495 水叮當的舞步


題目鏈接:水叮當的舞步

  我現在開始發題目鏈接了(主要還是因為懶得整理題面)……

  這道題一開始是看到MashiroSky在寫,於是我也開始寫這道題了(說白了就是狙擊他)……

  這道題看到這么小的范圍當然給人的第一感覺就是搜索了。於是我果斷寫了個搜索,后果很慘……我都沒敢交上去……

  后來想了各種優化,一路優化到了$80$分。最后的我想不出來了,於是就去翻了題解,終於弄全了。

  首先,這道題最好使用迭代加深搜索。因為普通的$dfs$太慢,而$bfs$空間又開不下(聽說某位大神使用$bfs$切掉了)。

  接下來就是各種剪枝。每次都要對左上角的聯通塊進行拓展,這一步很耗時間。於是我們可以考慮給每個格子染上色,已經在左上角聯通塊內的染為$1$,在邊上的染為$2$,其余的就是$3$了。於是每次拓展的時候我們只需可以找出所有顏色為$2$(是我們自己染上的顏色)的格子進行拓展即可。

  然后我們可以對當前狀態進行估價。設聯通塊外的顏色(輸入的顏色)數為$x$,那么至少需要$x$步才可以讓剩下的格子顏色相同。減掉一批。

  另外還剩下一個,那就是當改變顏色后左上角聯通塊大小沒有改變,那么這一步染色是無效的,可以直接減掉。

  大概就是這些了。這道題用到了估價函數,那么就是$A*$搜索?

  下面貼代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define N 9

using namespace std;

int a[N][N],n,now;//a數組是輸入的顏色,co數組是我自己染的顏色
int co[N][N],ans,yan[6],sheng;//yan數組標記剩下的每種顏色的數目,sheng就是剩余的不同種類顏色數
int zx[4]={1,-1,0,0},zy[4]={0,0,1,-1};

void color(int x,int y){//將(x,y)所在聯通塊納入左上角聯通塊
	if(!(--yan[a[x][y]])) sheng--;
	co[x][y]=1; now++;
	for(int k=0,i,j;k<4;k++){
		i=x+zx[k],j=y+zy[k];
		if(i>=1 && i<=n && j>=1 && j<=n && co[i][j]!=1){
			if(a[i][j]==a[x][y]) color(i,j);
			else co[i][j]=2;
		}
	}
}

bool pd(int x){//判斷聯通塊大小是否改變,順便進行染色
	bool ww=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(co[i][j]==2 && a[i][j]==x)
				color(i,j),ww=1;
	return ww;
}

bool dfs(int d){
	if(sheng>d) return 0;
	if(now==n*n) return 1;
	if(!d) return 0;
	int zan[N][N],col[6],nn=now,ns=sheng;
	for(int i=0;i<6;i++){
		memcpy(zan,co,sizeof(co));
		memcpy(col,yan,sizeof(yan));
		if(pd(i)){
			if(dfs(d-1)) return 1;
			memcpy(co,zan,sizeof(co));
			memcpy(yan,col,sizeof(yan));
			now=nn;sheng=ns;
		}
	}
	return 0;
}

int main(){
	File("a");
	while(scanf("%d",&n)==1 && n){
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				scanf("%d",&a[i][j]);
				co[i][j]=3;
			}
		now=sheng=0; color(1,1); yan[a[1][1]]=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(co[i][j]!=1) if(!(yan[a[i][j]]++)) sheng++;
		for(ans=0;;ans++)
			if(dfs(ans)){
				printf("%d\n",ans);
				break;
			}
	}
	return 0;
}

注意!

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



 
  © 2014-2022 ITdaan.com