NKOJ 2440 數字消除遊戲【迭代加深+剪枝】
阿新 • • 發佈:2018-12-15
問題描述
在一個n*n的方形棋盤上玩消除遊戲,棋盤上佈滿了數字。 每一步,玩家可以任選一個數字x,用它填充座標為(1,1)格子所在連通區域,該區域的數字都會變成x。(如果兩個數字相同且相鄰,我們稱這兩個數字連通。相鄰是上下左右四方向)。 當整個棋盤的數字都相同時,就可以將整個棋盤上的數字消除掉,遊戲結束。 問,最少需要幾次操作就能消除所有數字。
輸入格式
有若干組測試資料(不超過20組),對於每組測試資料: 第一行,一個整數n,表示棋盤的尺寸。 接下來一個n*n的數字矩陣,表示遊戲的初始局面。 當輸入的n==0時,輸入結束。
輸出格式
對於每組測試資料,輸出一行,一個整數,表示最少需要的運算元。
#include <map> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define rep(i,x,y) for(ll i=(x);i<=(y);i++) #define repl(i,x,y) for(ll i=(x);i<(y);i++) #define repd(i,x,y) for(ll i=(x);i>=(y);i--) using namespace std; const ll N=10; ll n,tim,mp[N][N],vis[N][N]; ll dx[4]={0,0,-1,1}; ll dy[4]={-1,1,0,0}; map<ll,ll>Hash; inline ll read() { ll x=0;char ch=getchar();bool f=0; while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?-x:x; } void dfs(ll x,ll y,ll z) { vis[x][y]=1; rep(i,0,3) { ll tx=x+dx[i],ty=y+dy[i]; if(tx<1||ty<1||tx>n||ty>n||vis[tx][ty]==1) continue; vis[tx][ty]=2; if(mp[tx][ty]==z) dfs(tx,ty,z); } } ll getleft() { ll ret=0,col[7]={0}; rep(i,1,n) rep(j,1,n) if(!col[mp[i][j]]&&vis[i][j]!=1) { col[mp[i][j]]=1;ret++; }return ret; } ll getfill(ll z) { ll ret=0; rep(i,1,n) rep(j,1,n) if(mp[i][j]==z&&vis[i][j]==2) { ++ret;dfs(i,j,z); }return ret; } ll idastar(ll dep,ll lim) { ll ret=getleft(); if(dep+ret>lim) return 0; if(!ret) return 1; ll vvis[N][N]={0}; rep(i,1,tim) { memcpy(vvis,vis,sizeof(vis)); if(getfill(i)&&idastar(dep+1,lim)) return 1; memcpy(vis,vvis,sizeof(vis)); } return 0; } int main() { while(true) { n=read(); if(!n) return 0; while(Hash.size()) Hash.erase(Hash.begin()); tim=0; rep(i,1,n) rep(j,1,n) { mp[i][j]=read(); if(!Hash[mp[i][j]]) Hash[mp[i][j]]++;mp[i][j]=Hash[mp[i][j]]; } memset(vis,0,sizeof(vis)); dfs(1,1,mp[1][1]); rep(dep,0,N*N) if(idastar(0,dep)) { printf("%lld\n",dep);break; } } return 0; }