Nuts for nuts.. UVA - 10944狀壓dp
阿新 • • 發佈:2019-01-05
文章目錄
Nuts for nuts… UVA - 10944
題意:
n*m的方格中,有一個起點和num個核桃,問把所有的核桃都取了,然後回到原地的最小步數,可以往八個方向移動
分析:
先把起點和核桃都從圖中摳出來,然後兩兩之間的距離是
,之後狀態壓縮dp
dp[i][j] 代表最後一個取的核桃編號是i,現在的狀態是j,j的二進位制為1,代表相應編號的核桃已經取過
假設當前狀態是i,j
那麼它可以更新的狀態是
其中 j&(1<<k)-1 == 0
參考程式碼
const int maxn = 30;
const int maxm = 1<<16;
int dp[maxn][maxm];
char s[maxn];
int Map[maxn][maxn];
int x[maxn],y[maxn];
int num,n,m,ans,maxz;
int main(void){
while(~scanf("%d%d",&n,&m)){
num = 0;
// getchar();
for(int i = 0;i < n; ++i){
scanf(" %s",s);
for(int j = 0;j < m; ++j){
if(s[j] == 'L')
x[0] = i,y[0] = j;
else if(s[j] == '#')
x[++num] = i,y[num] = j;
}
}
// cout<<"DEBUG"<<endl;
if(num == 0){
cout<<0<<endl;
continue;
}
for(int i = 0;i <= num; ++i){
for(int j = 0;j <= num; ++j){
Map[i][j] = max(abs(x[i]-x[j]),abs(y[i]-y[j]));
// cout<<Map[i][j]<<endl;
}
}
maxz = (1<<num)-1;
// cout<<maxz<<endl;
for(int i = 0;i <= num;++i)
for(int j = 0;j <= maxz; ++j)
dp[i][j] = INF/10;
for(int i = 1;i <= num; ++i)
dp[i][1<<(i-1)] = Map[0][i];
// DEBUG;
// cout<<num<<endl;
for(int i = 0;i <= maxz; ++i){
for(int j = 1;j <= num; ++j){
int result = i&(1<<(j-1));
if(result == 0){
result = i|(1<<(j-1));
for(int k = 1;k <= num; ++k){
dp[j][result] = min(dp[j][result],dp[k][i]+Map[k][j]);
}
}
}
}
// DEBUG;
int ans = INF;
for(int i = 1;i <= num; ++i)
ans = min(ans,dp[i][maxz]+Map[i][0]);
cout<<ans<<endl;
}
return 0;
}