题意: 有 n个发电站 编号 1到n ,每个发电站有一个pow 值, m条边 每条边有一个cost 值, 要求 选出一些点,使得这些点的pow值>sum(pow)/2 并且 从0号到每个点的最短距离和最小。 最短路+01背包, 0号到每个点的最短距离作为价值 , pow作为花费。
#include<bits/stdc++.h>
using namespace std;
struct node
{
int to ,val;
};
const int mx = 105;
int dis[mx];
int dp[2000010];
int powv[101];
const int inf = 1e9;
int mp[101][101];
int n;
void floyd()
{
for(int k =0; k<=n; k++)
{
for(int i =0; i<=n; i++)
{
for(int j=0; j<=n; j++)
{
mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
//memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i =1 ;i<=2000000;i++)
dp[i] = inf;
int m;
scanf("%d%d",&n,&m);
for(int i =0; i<=n; i++)
{
for(int j =0; j<=n; j++)
{
mp[i][j] = inf;
} mp[i][i]=0;
}
int x,y,z;
for(int i = 1; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&z);
if(mp[x][y]>z)
{
mp[x][y] = mp[y][x] = z;
}
}
floyd();
int sum = 0;
for(int i = 1; i<=n; i++)
{
scanf("%d",&powv[i]);
sum+=powv[i];
}
for(int i = 1; i<=n; i++)
{
dis[i] = mp[0][i];
}
dp[0]=0;
for(int i = 1; i<=n; i++)
{
for(int j=sum; j>=powv[i]; j--)
{
dp[j] = min(dp[j],dp[j- powv[i]]+ dis[i]);
}
}
int ans = 1e9;
int g ;
g= sum/2+1;
for(int i = sum; i>=g; i--)
{
ans =min(ans,dp[i]);
}
if(ans!=inf)
{
cout<<ans<<endl;
}
else
{
printf("impossible\n");
}
}
return 0;
}