题目来源:HDU 3339 In Action
题意:有一个系统要去破坏 该系统是有n个点组成的图 每个点有一个权值
可以从0排除任意个机器人 去占领一个点 每个机器只能占领一个地方 所有机器人占领点的权值之和大于所有点权值之和的一半(不能等于) 就算破环成功
求在破坏的情况下所有机器人走过的路径之和最小
思路:简而言之 就是选出若干个点 他们的和大于总数的一半 并且走的路最短
转化成背包问题 总体积为所有点权值的和 每个物品的体积是该个点的权值 价值是0到个点的距离 0到各个点的距离可以用floyd求出 最后01背包求最小值就可以了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 110; const int maxm = 10010; int a[maxn][maxn]; int b[maxn]; int dp[maxm]; int n, m; void floyd() { for(int k = 0; k <= n; k++) for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) if(a[i][j] > a[i][k] + a[k][j]) a[i][j] = a[i][k] + a[k][j]; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) { if(i == j) a[i][j] = 0; else a[i][j] = 99999999; } for(int i = 1; i <= m; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); if(a[u][v] > w) a[u][v] = a[v][u] = w; } floyd(); int sum = 0; for(int i = 1; i <= n; i++) { scanf("%d", &b[i]); sum += b[i]; } //printf("%d\n", sum); for(int i = 1; i <= sum; i++) dp[i] = 99999999; dp[0] = 0; for(int i = 1; i <= n; i++) { for(int j = sum; j >= b[i]; j--) { dp[j] = min(dp[j], dp[j-b[i]]+a[0][i]); } } int ans = 99999999; for(int i = sum/2+1; i <= sum; i++) { ans = min(ans, dp[i]); } if(ans == 99999999) puts("impossible"); else printf("%d\n", ans); } return 0; }
HDU 3339 In Action 价值为最短路的背包,布布扣,bubuko.com
原文:http://blog.csdn.net/u011686226/article/details/23002755