hdu 3339 最短路+背包
/* 题意:给出一个0~n组成的图,1~n的点上分布着值为pow的电站,给出图的m条边以及 距离,从0出发到n个点中的x个点的行走距离和最小,且x个点的pow之和必须超过总的pow 和的一半; 题解:最短路+01背包 先求出0到所有点的最短距离,然后通过以行走的距离为背包,pow的和为价值,设将所有 点遍历走的距离值为sum,即要求0~sum的dp值,即当距离为v时,dp[v]为pow的最大的和, 因此dp完之后从0~sum遍历找出最小的v满足pow的和大于总和一半即可。 注意:重边、不连通的点、是多于一半的power,等于不行 */ #include <iostream> #include <vector> #include <cstring> #include <algorithm> #define Max 1000000001 using namespace std; struct nod { int power; int oil; }s[105]; int p; int dp[60050],dist[105]; int map[105][105]; bool vis[105]; void dijkstra(int next, int n)//迪杰斯特拉算法求最短路,next为起点 { for(int i=0; i<=n; i++) dist[i] = Max; memset(vis,false,sizeof(vis)); dist[next] = 0; for(int i=0; i<=n; i++) { int mindis = Max; for(int j=0; j<=n; j++) { if (!vis[j] && dist[j] < mindis)//找出未访问的点中路径最短的点并赋给node { mindis = dist[j]; next = j; } } if (mindis == Max)//当点已经遍历完,break; break; vis[next] = true; for(int j=0; j<=n; j++) if (!vis[j] && map[next][j] > 0 && dist[next]+map[next][j] < dist[j]) //以next为基点对其它未访问的点进行松弛 dist[j] = dist[next]+map[next][j]; } } bool cmp(nod a, nod b) { return a.oil < b.oil; } int main(void) { int n,q,fr,to,price,allpower; cin >> n; while (n--) { cin >> p >> q; allpower = 0; for(int i=0; i<=p; i++) for(int j=0; j<=p; j++) { map[i][j] = Max; } while (q--) { cin >> fr >> to >> price; if (map[fr][to] > price) map[fr][to] = map[to][fr] = price; } for(int i=1; i<=p; i++) { cin >> s[i].power; allpower += s[i].power; } dijkstra(0,p); int alloil, num; alloil = 0; num = 0; for(int i=1; i<=p; i++) { if (dist[i] < Max) { alloil += dist[i]; num++; } s[i].oil = dist[i]; } sort(s+1,s+p+1,cmp); int ans = 0; memset(dp,0,sizeof(dp)); for(int i=1; i<=num; i++) for(int v = alloil; v >= s[i].oil; v--) dp[v] = max(dp[v],dp[v-s[i].oil] + s[i].power); int i; for(i=0; i<=alloil; i++) if (dp[i] >= allpower/2+1) break; if (i <= alloil) cout << i << endl; else cout << "impossible" << endl; } return 0; }