题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3339
In Action
题目大意:给你n个点,每个点都有一个power值,再给你m条路(路之间代表油费),求从0出发到某些点 使得 油量消耗最少且power值达到一半。
可以floyd或者spfa求出0到各点的距离 dis[ maxm ]。
然后就可以转化为:从dis[]中挑出某些点,使得距离和最小且power值达到某个值。
从01背包中可以发现:从给定的一些物品中挑出一些放入一个背包中,使得不超过背包体积。
这样我们同样可以把dis当做每个物品的体积,power当做价值。
然后从dp中搜到一个power值满足条件的最小的 i 即可!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 1e9
using namespace std;
int n,m;
int edge[110][110];
int cost;
int power[110];
int dp[1000010];
int floyd()
{
int i,j,k,cost=0;
for(k=0;k<=n;k++)
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j]);
for(i=1;i<=n;i++)
if(edge[0][i]!=INF)
cost+=edge[0][i];
return cost;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i,j,a,b,c,sum,ans=INF,res=0;
scanf("%d%d",&n,&m);
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
{
edge[i][i]=0;
edge[i][j]=edge[j][i]=INF;
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
edge[a][b]=edge[b][a]=min(edge[a][b],c);
}
for(i=1;i<=n;i++)
{
scanf("%d",&power[i]);
res+=power[i];
}
sum=floyd();
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
for(j=sum;j>=edge[0][i];j--)
dp[j]=max(dp[j],dp[j-edge[0][i]]+power[i]);
for(i=0;i<=sum;i++)
if(dp[i]>=(res/2+1)&&dp[i]<ans)
{
ans=i;
break;
}
if(ans==INF)
printf("impossible\n");
else
printf("%d\n",ans);
}
return 0;
}