题意比较容易明白:每个点有一个pow值,代表电力,要求从0号点派出一些坦克,占领这些点,使得占领的点的pow值总和大于整个图中的pow总之。且坦克耗费的总油最小,坦克数量不限。
思路,在求得单元最短路之后,以pow为背包,路径长度为物品,求解01背包。然后从pow总值的一半开始往后扫,得出油量(物品)最小值。
#include <iostream>
#include <queue>
#include <vector>
#include <stdio.h>
#define INF 100000000
using namespace std;
int N,M;
int dist[105];
int dp[10000000],pow[105];
struct node
{
int E,W;
node(int ee,int ww):E(ee),W(ww){}
node() {}
friend bool operator<(node n1,node n2)
{
return n1.W>n2.W;
}
};
vector<vector<node> >v;
void dijikstra()
{
for(int i=1;i<=N;i++)
dist[i]=INF;
dist[0]=0;
priority_queue<node> Q;
Q.push(node(0,0));
while(!Q.empty())
{
node now=Q.top();
Q.pop();
int S=now.E;
for(int i=0;i<v[S].size();i++)
{
if(dist[S]+v[S][i].W<dist[v[S][i].E])
{
dist[v[S][i].E]=dist[S]+v[S][i].W;
Q.push(node(v[S][i].E,dist[v[S][i].E]));
}
}
}
}
int main()
{
int T,s,e,w,sum,ans;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
v.clear();
v.resize(N+1);
sum=0;
while(M--)
{
scanf("%d%d%d",&s,&e,&w);
v[s].push_back(node(e,w));
v[e].push_back(node(s,w));
}
for(int i=1;i<=N;i++)
{
scanf("%d",&pow[i]);
sum+=pow[i];
}
dijikstra();
for(int i=1;i<=sum;i++)
dp[i]=INF;
dp[0]=0;
for(int i=1;i<=N;i++)
{
for(int j=sum;j>=pow[i];j--)
{
dp[j]=min(dp[j],dp[j-pow[i]]+dist[i]);
}
}
ans=INF;
for(int i=sum/2+1;i<=sum;i++)
ans=min(ans,dp[i]);
if(ans==INF)
cout<<"impossible"<<endl;
else
cout<<ans<<endl;
}
return 0;
}