題目鏈接:水叮當的舞步
我現在開始發題目鏈接了(主要還是因為懶得整理題面)……
這道題一開始是看到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; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。