T組數據。有足夠坦克在0點,現有P個據點,Q條雙向路,每條路有長度,坦克開單位長度的路需要油1升,每個據點提供一定電力。現需要佔領一半以上的電力,坦克停留在一個據點即佔領該據點並獲得相應的電力。問最少需要多少油。
Spfa求0到各個據點的最短路,之後以長度爲揹包容量,以電力爲物品價值,做01揹包。注意有重邊,這坑了幾次。
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int inf = 1 << 20 ;
const int MAX = 105 ;
int n , m , sum ;
int map[MAX][MAX] = {0} ;
int dis[MAX] = {0} ;
int ele[MAX] = {0} ;
int dp[10005] = {0} ;
bool had[MAX] = {0} ;
queue <int> q ;
int Max(int x , int y) {
return (x > y)? x : y ;
}
void init() {
sum = 0 ;
memset(had , 0 , sizeof(had)) ;
memset(dp , 0 , sizeof(dp)) ;
for (int i = 0 ; i <= n ; i ++) {
for (int j = i + 1 ; j <= n ; j ++) {
map[i][j] = map[j][i] = inf ;
}
}
}
void spfa() {
dis[0] = 0 ;
for (int i = 1 ; i <= n ; i ++) {
dis[i] = inf ;
}
q.push(0) ; had[0] = 1 ;
while (!q.empty()) {
int t = q.front() ; q.pop() ;
had[t] = 0 ;
for (int i = 1 ; i <= n ; i ++) {
if (dis[i] > dis[t] + map[t][i]) {
dis[i] = dis[t] + map[t][i] ;
if (!had[i]) {
had[i] = 1 ;
q.push(i) ;
}
}
}
}
}
void DP() {
for (int i = 1 ; i <= n ; i ++) {
if (dis[i] != inf) {
sum += dis[i] ;
}
}
for (int i = 1 ; i <= n ; i ++) {
for (int v = sum ; v >= dis[i] ; v --) {
if (v >= dis[i]) {
dp[v] = Max(dp[v] , dp[v-dis[i]] + ele[i]) ;
}
}
}
}
int main() {
//freopen("in.txt" , "r" , stdin) ;
int T ;
cin >> T ;
while (T --) {
cin >> n >> m ;
init() ;
while (m --) {
int st , ed , d ;
cin >> st >> ed >> d ;
if (d < map[st][ed]) {
map[st][ed] = map[ed][st] = d ;
}
}
spfa() ;
int all = 0 ;
for (int i = 1 ; i <= n ; i ++) {
cin >> ele[i] ;
all += ele[i] ;
}
DP() ;
int ans = -1 , half = all >> 1 ;
for (int i = 0 ; i <= sum ; i ++) {
//printf("%d,%d\n",i,dp[i]);
if (dp[i] > half) {
ans = i ;
break ;
}
}
if (ans == -1) printf("impossible\n") ;
else cout << ans << endl ;
}
return 0;
}