http://acm.hdu.edu.cn/showproblem.php?pid=1074
状压dp,记录路径
求最小值的状压dp非常裸,5分钟就写好了,记录路径有点麻烦,之前没怎么处理过这种问题
我的方法是用一个map建立当前状态和前驱状态的映射,输出要按字典序,因为已经按字典序从大到小排好了,所以状态值比较小的优先(字典序小)
#include <iostream> #include <cstdio> #include <cstring> #include <map> using namespace std; const int INF = 0xfffffff; struct fuck{ int w, pre; }dp[1<<15]; struct node{ char name[105]; int D, C; }p[16]; int cal(int x){ int res = 0, cnt = 0; while(x){ if(x & 1){ res += p[cnt].C; } cnt++; x >>= 1; } return res; } int cnt(int x){ int res = 0; while(x){ if(x & 1){ res++; } x >>= 1; } return res; } int cal1(int x, int y){ int res = 0; while(1){ if((x&1) != (y&1)){ return res; } res++; x >>= 1; y >>= 1; } } int ans[25], ct; int main(){ int T; scanf("%d", &T); while(T--){ int n; scanf("%d", &n); for(int i = 0; i < (1<<n); i++) dp[i].w = INF; int xx = 0; while(1){ dp[(1<<xx)].pre = 0; xx++; if(xx == n) break; } for(int i = 0;i < n; i++){ scanf("%s %d %d", p[i].name, &p[i].D, &p[i].C); if(p[i].C > p[i].D) dp[1<<i].w = p[i].C - p[i].D; else dp[1<<i].w = 0; } map <int, int> mp; for(int i = 0; i < (1<<n); i++){ for(int j = 0; j < n; j++){ if(i&(1<<j)){ if(cal(i) > p[j].D){ if(dp[i].w > dp[i^(1<<j)].w + cal(i) - p[j].D){ dp[i].w = dp[i^(1<<j)].w + cal(i) - p[j].D; dp[i].pre = i^(1<<j); mp[i] = i^(1<<j); } else if(dp[i].w == dp[i^(1<<j)].w + cal(i) - p[j].D && dp[i].pre > (i^(1<<j))){ dp[i].pre = i^(1<<j); mp[i] = i^(1<<j); } //dp[i] = min(dp[i], dp[i^(1<<j)] + cal(i) - p[j].D); } else{ if(dp[i].w > dp[i^(1<<j)].w){ dp[i].w = dp[i^(1<<j)].w; dp[i].pre = i^(1<<j); mp[i] = i^(1<<j); } else if(dp[i].w == dp[i^(1<<j)].w && dp[i].pre > (i^(1<<j))){ dp[i].pre = i^(1<<j); mp[i] = i^(1<<j); } //dp[i] = min(dp[i], dp[i^(1<<j)]); } } } } printf("%d\n", dp[(1<<n)-1]); int now = (1<<n) - 1; ct = 0; while(now){ ans[ct++] = cal1(now, mp[now]); now = mp[now]; } for(int i = n - 1; i >= 0; i--){ printf("%s\n", p[ans[i]].name); } } return 0; }