题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4284
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int maxn = 105; const int maxm = 16; const int INF = 0x3f3f3f3f; int dp[maxm][1<<maxm]; //dp[i][S],当前在i,访问完S中的点还剩的最大money数。最后判断是不是大于等于0. int dist[maxn][maxn]; //dist[i][j] 表示从i到j,所需的最小花费。 int N,M,Money,H; int C[maxm],D[maxm]; int Must[maxm]; int main() { //freopen("E:\acm\input.txt","r",stdin); int T; cin>>T; while(T--){ cin>>N>>M>>Money; for(int i=0;i<=N;i++) for(int j=0;j<=N;j++) dist[i][j] = INF; for(int i=1;i<=N;i++) dist[i][i] = 0; for(int i=1;i<=M;i++){ int u,v,w; scanf("%d %d %d",&u,&v,&w); if(dist[u][v] > w) dist[u][v] = dist[v][u] = w; //这个地方没考虑。 } cin>>H; for(int i=0;i<H;i++) scanf("%d %d %d",&Must[i],&C[i],&D[i]); for(int k=1;k<=N;k++) for(int i=1;i<=N;i++) if(dist[i][k] < INF){ for(int j=1;j<=N;j++){ if(dist[k][j] < INF){ dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]); } } } memset(dp,-0x3f,sizeof(dp)); for(int i=0;i<H;i++){ if(Money -dist[1][Must[i]]- D[i]>=0) dp[i][1<<i] = Money - dist[1][Must[i]] - D[i] + C[i]; } int All = (1<<H) - 1; //这个地方WA for(int S=0;S<=All;S++){ //理解偏差; for(int i=0;i<H;i++){ if(!((1<<i)&S) || dp[i][S] < 0) continue; for(int j=0;j<H;j++){ if(((1<<j)&S) || i == j ) continue; if(dp[i][S] - dist[Must[i]][Must[j]]- D[j] >= 0 ){ dp[j][1<<j|S] = max(dp[j][1<<j|S] , dp[i][S] - dist[Must[i]][Must[j]] - D[j] + C[j]); } } } } bool flag = false; for(int i=0;i<H;i++){ if(dp[i][All] - dist[Must[i]][1] >= 0){ flag = true; break; } } if(flag) printf("YES "); else printf("NO "); } }