hdu 4284
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4284
题意:给出一些城市,从1出发,旅游一圈回到1,由于花费可能不够,所以选择一些城市打工,打工之前需要花费d买一个证,工资为c。选中的城市必须去工作一次,而且只能工作一次,问能不能完成旅行
mark:先用floyd预处理,记住一定要把断点放在最外层循环!!!状态压缩dp。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> #include <map> using namespace std; const int INF = (1 << 28); int n,m,mon,h; int adj[110][110], s[20], c[20], d[20]; int dp[1 << 16][20]; void init() //Floyd预处理。!!!找了一小时啊,断点一定要放在最外层循环! { for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) for(int k = 0; k < n; k++) if(i != j && i != k && j != k) adj[j][k] = min(adj[j][k], adj[j][i]+adj[i][k]); } bool find() { for(int i = 0; i < h; i++) if(dp[(1 << h)-1][i] >= adj[s[i]][0]) return 1; return 0; } int main() { int t; int i,j,k; int aa,bb,cc; scanf("%d", &t); while(t--) { scanf("%d%d%d", &n, &m, &mon); for(i = 0; i < n; i++) for(j = 0; j < n; j++) { if(i == j) adj[i][i] = 0; else adj[i][j] = INF; } for(i = 0; i < m; i++) { scanf("%d%d%d", &aa, &bb, &cc); aa--,bb--; adj[aa][bb] = min(adj[aa][bb], cc); adj[bb][aa] = adj[aa][bb]; } init(); scanf("%d", &h); int f = -1; for(i = 0; i < h; i++) { scanf("%d%d%d", s+i, c+i, d+i); s[i]--; if(s[i] == 0) f = i; } memset(dp, -1, sizeof(dp)); if(f == -1) //加一个空点,当作起始点。 { s[h] = c[h] = d[h] = 0; f = h++; } if(mon >= d[f]) dp[1 << f][f] = mon-d[f]+c[f]; dp[0][f] = mon; for(i = 0; i < (1 << h); i++) for(j = 0; j < h; j++) { if(dp[i][j] == -1) continue; for(k = 0; k < h; k++) { if(i & (1 << k)) continue; if(dp[i][j] >= adj[s[j]][s[k]]+d[k]) dp[i|(1<<k)][k] = max(dp[i|(1<<k)][k], dp[i][j]-adj[s[j]][s[k]]-d[k]+c[k]); } } puts(find() ? "YES" : "NO"); } return 0; }