今年天津赛区网络赛的一道题,比赛的时候跟强哥讨论了一下,他的思路很明确,然后就让他去写了。。。赛后偶翻了翻这个题。。。额,还不错的状态dp把。。。就是让我给写搓了。。。贡献n次wa。。。
题目是给一下点之间的花费,构成一个图(图不是很大,最多100*100)。然后指定一些必须访问的点。并且这些点上有一个先花费Di再收入Ci的过程,问能否实现访问所有这些点。。。
因为指定的点数最多为15,加上1号点最多才17,所以直接用状态压缩就可以。先用floyd找出任意两点间的最小花费。然后dp[status][pos]表示当前状态为status并且最后访问的点为pos时,所有的资金数。最后找一个dp[(1<<h)-1][i] - dis[p[i].num][p[start].num] >= 0的点,如果存在则是YES,否则是NO
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #include <queue> #include <map> #include <functional> #include <numeric> #include <sstream> #include <stack> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) i&(-i) const int eps = 1e-8; typedef long long LL; const int inf = ~0u>>2; using namespace std; const int N = 110; const int M = (1<<16) + 10; int dis[N][N]; int dp[M][20]; int n, m, my, h, st; struct node { int i; int c; int d; node() {} node(int x, int y, int z) : i(x), c(y), d(z) {} bool operator < (const node cmp) const { return i < cmp.i; } }p[20]; void init() { int i, j; for(i = 1; i<= n; ++i) { for(j = 1; j <= n; ++j) dis[i][j] = (i == j) ? 0 : inf; } } void floyd() { int i, j, k; for(k = 1; k <= n; ++k) { for(i = 1; i <= n; ++i) { for(j = 1; j <= n; ++j) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } } bool solve() { int status, i, j; CL(dp, -1); for(i = 0; i < h; ++i) { //初始化 if(my - dis[p[i].i][p[st].i] - p[i].d >= 0) dp[1<<i][i] = my - dis[p[i].i][p[st].i] - p[i].d + p[i].c; } for(status = 0; status < (1<<h); ++status) { for(i = 0; i < h; ++i) { if(dp[status][i] == -1) continue; for(j = 0; j < h; ++j) { if(status&(1<<j)) continue; if(dp[status][i] - dis[p[i].i][p[j].i] - p[j].d >= 0) { dp[status|(1<<j)][j] = max(dp[status|(1<<j)][j], dp[status][i] - dis[p[i].i][p[j].i] - p[j].d + p[j].c); } } } } for(i = 0; i < h; ++i) { if(dp[(1<<h)-1][i] - dis[p[i].i][p[st].i] >= 0) break; } if(i >= h) return false; return true; } int main() { //freopen("data.in", "r", stdin); int T, x, y, z, i; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &m, &my); init(); while(m--) { scanf("%d%d%d", &x, &y, &z); if(z < dis[x][y]) { dis[x][y] = dis[y][x] = z; } } floyd(); scanf("%d", &h); st = -1; //st表示初始点1的下标 for(i = 0; i < h; ++i) { scanf("%d%d%d", &p[i].i, &p[i].c, &p[i].d); if(p[i].i == 1) st = i; } if(st == -1) { p[h] = node(1, 0, 0); //如果没有再加进去。 st = h++; } if(solve()) puts("YES"); else puts("NO"); } return 0; }