题意是出发点有好多坦克(无限个),有很多个发电站,每个发电站有一个价值,并且每条路都有一个距离,现在要求在满足坦克占领的发电站的价值大于等于全部节点价值的一半的前提下,尽量让路程最短
首先最短路,然后以0到各个点的距离作为背包容量,各个的价值位置物品价值,于是dp背包解决,注意一下处理的一些细节(看代码)
/* * this code is made by LinMeiChen * Problem: * Type of Problem: * Thinking: * Feeling: */ #include<iostream> #include<algorithm> #include<stdlib.h> #include<string.h> #include<stdio.h> #include<math.h> #include<string> #include<vector> #include<queue> #include<list> using namespace std; typedef long long lld; typedef unsigned int ud; #define oo 1000001 #define maxn 102 #define maxm 10010 int dp[maxm*100]; int value[maxn]; int dis[maxn], mark[maxn]; int map[maxn][maxn]; int n; void Dijkstra() { for (int i = 1; i <= n; i++) { mark[i] = 0; dis[i] = map[0][i]; } mark[0] = 1; dis[0] = 1; int t = n; while (t--) { int min = oo, k; for (int i = 1; i <= n;i++) if (dis[i] < min && !mark[i]) { min = dis[i]; k = i; } if (min == oo) break; mark[k] = 1; for (int i = 1; i <= n; i++) { if (dis[k] + map[k][i] < dis[i] && !mark[i]){ dis[i] = dis[k] + map[k][i]; } } } } int main() { int m, u, v, w, T, V, D; scanf("%d", &T); while (T--) { V = D = 0; scanf("%d%d", &n, &m); for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++) map[i][j] = oo; for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &w); if (map[u][v] > w) map[u][v]= map[v][u] = w; } for (int i = 1; i <= n; i++) { scanf("%d", &value[i]); V += value[i]; } Dijkstra(); for (int i = 1; i <= n; i++) { if (dis[i] >= oo)//这里直接跳过不可达的点 continue; D += dis[i]; } memset(dp, 0, sizeof dp); for (int i = 1; i <= n; i++) { if (dis[i] >= oo)//在dp的时候跳过这个点,相当于背包没有这个物品一样 continue; for (int j = D; j >= dis[i]; j--) { dp[j] = max(dp[j - dis[i]] + value[i], dp[j]); } } int find = false; for (int i = 1; i <= D; i++) { if (dp[i] >= V / 2 + 1) { printf("%d\n", i); find = true; break; } } if (!find) printf("impossible\n"); } return 0; }