LightOJ1057 Collecting Gold(状压DP)

这道题可以想到几点:

  • 整个行程可以看作一次次的行走,每次行走都是用最短的路程从某一非空点到达另外一非空点;
  • 两点间最少的步数是二者x和y坐标差的最大值;
  • 返回原点这个过程,肯定是取完最后一个黄金后直接用最少的步数从这儿出发回到原点。

然后就是状压DP了:

dp[u][S]:经过非空点集S后到达u点最少的步数

转移就枚举从哪儿到达u点的。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define INF (1<<29)
 6 int x[16],y[16],cnt;
 7 int d[16][1<<16];
 8 int main(){
 9     int t,n,m;
10     scanf("%d",&t);
11     for(int cse=1; cse<=t; ++cse){
12         scanf("%d%d",&n,&m);
13         cnt=0;
14         char c;
15         int sx,sy;
16         for(int i=0; i<n; ++i){
17             for(int j=0; j<m; ++j){
18                 scanf(" %c",&c);
19                 if(c=='x') sx=i,sy=j;
20                 else if(c=='g') x[cnt]=i,y[cnt]=j,++cnt;
21             }
22         }
23         x[cnt]=sx,y[cnt]=sy,++cnt;
24 
25         for(int i=0; i<16; ++i){
26             for(int j=0; j<(1<<16); ++j) d[i][j]=INF;
27         }
28         d[cnt-1][1<<cnt-1]=0;
29         for(int i=(1<<cnt-1)+1; i<(1<<cnt); ++i){
30             for(int j=0; j<cnt; ++j){
31                 if(((i>>j)&1)==0 || j==cnt-1) continue;
32                 for(int k=0; k<cnt; ++k){
33                     if(((i>>k)&1)==0 || k==j) continue;
34                     d[j][i]=min(d[j][i],d[k][i^(1<<j)]+max(abs(x[j]-x[k]),abs(y[j]-y[k])));
35                 }
36             }
37         }
38         int res=INF;
39         for(int i=0; i<cnt; ++i) res=min(res,d[i][(1<<cnt)-1]+max(abs(x[i]-x[cnt-1]),abs(y[i]-y[cnt-1])));
40         printf("Case %d: %d
",cse,res);
41     }
42     return 0;
43 }
原文地址:https://www.cnblogs.com/WABoss/p/5133794.html