HDU 4385 Moving Bricks【状态压缩DP】
题意: 有 n 个砖块,知道了每个砖块的位置和人的起始位置 st,现在要把这 n 块砖搬到st,每次最多能搬回两块砖,搬砖块的体力耗费为两个地点距离的平方,
问搬回这 n 块砖所需消耗的最小体力是多少,并按字典序输出搬砖块的顺序。
分析: dp[i] 表示 i 状态的最小值
dp[i] = max(dp[i],dp[i |(1<<j)]+2*dis[n][j]) 搬一块砖的时候
dp[i] = max(dp[i],dp[i|(1<<j)|(1<<k)]+dis[n][j]+dis[j][k]+dis[n][k]) 搬两块砖的时候
同时用pre[] 记录状态转移路径
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define clr(x)memset(x,0,sizeof(x)) #define min(a,b)(a)<(b)?(a):(b) #define INF 0x1f1f1f1f #define N 21 struct node { int x,y; }p[N],begin; int dis(node a,node b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } int g[N][N]; int dp[1<<N]; int pre[1<<N]; struct ans { int fi,se,num; }res[N]; bool cmp(ans a,ans b) { return a.fi<b.fi; } int main() { int ca=1,n,i,j,k,t; scanf("%d",&t); while(t--) { scanf("%d %d",&begin.x,&begin.y); scanf("%d",&n); p[n]=begin; for(i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); memset(dp,INF,sizeof(dp)); pre[0]=0; int st=1<<n; dp[0]=0; for(i=0;i<=n;i++) for(j=0;j<=n;j++) g[i][j]=dis(p[i],p[j]); printf("Case %d:\n",ca++); int stat,tmp,ss; for(i=0;i<st;i++) { for(j=0;j<n;j++) { if((1<<j)&i) continue; stat=i|(1<<j); tmp=dp[i]+g[n][j]*2; if(tmp<dp[stat]) { dp[stat]=tmp; pre[stat]=i; } for(k=j+1;k<n;k++) { if((1<<k)&i) continue; ss=stat|(1<<k); tmp=dp[i]+g[n][j]+g[j][k]+g[n][k]; if(tmp<dp[ss]) { dp[ss]=tmp; pre[ss]=i; } } } } st-=1; printf("%d\n",dp[st]); int top=0; while(st) { stat=pre[st]^st; st=pre[st]; res[top].num=0; for(i=0;i<n;i++) if((1<<i)&stat) { res[top].num++; if(res[top].num==1) res[top].fi=i+1; else res[top].se=i+1; } top++; } sort(res,res+top,cmp); for(i=0;i<top;i++) { if(res[i].num==1) printf("%d%c",res[i].fi,i==top-1?'\n':' '); else printf("%d %d%c",res[i].fi,res[i].se,i==top-1?'\n':' '); } } return 0; }