题意:
AC大神要引爆核弹毁灭世界,他有n个电站,每个电站有一定电量,引爆需要至少一半的电量。
从原点0可以派出足够多的tank去占领,占领电站就能切断该电站对引爆核弹电量的供应。原点与电站之间构成一副无向带权图,权表示从一个点到另一个点tank的耗油量,求拯救世界需要最少的油耗。
题解:
一遍最短路,算出占领每个点最少需要油耗。
然后一个点有两个属性,油耗和电量,将油耗当重量,电量当价值,0/1背包即可。
代码:
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年1月16日, 下午3:12
*/
#include <cstdlib>
#include <stdio.h>
#include <memory.h>
using namespace std;
#define MAXN 105
#define INF 2000000
int n,d[MAXN][MAXN],cnt[MAXN][MAXN],a[MAXN][MAXN];
void Floyd()
{
int i,j,k;
for(k=0;k<=n;k++)
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
if (a[i][k]+a[k][j]<a[i][j])
a[i][j]=a[i][k]+a[k][j];
}
int v[MAXN];
int f[1000005];
int main(int argc, char** argv)
{
int m,i,j,x,y,sum,z,psum,t;
scanf("%d",&t);
while(scanf("%d %d",&n,&m)!=EOF)
{
if (n==0&&m==0) break;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
a[i][j]=INF;
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
if (a[x][y]>z)
a[x][y]=a[y][x]=z;
}
psum=0;
for(i=1;i<=n;i++)
{
scanf("%d",&v[i]);
psum+=v[i];
}
Floyd();
sum=0;
for(i=1;i<=n;i++)
if (a[0][i]<INF)
sum+=a[0][i];
for(i=0;i<=sum;i++)
f[i]=0;
for(i=1;i<=n;i++)
for(j=sum;j>=a[0][i];j--)
if (f[j-a[0][i]]+v[i]>f[j])
f[j]=f[j-a[0][i]]+v[i];
int ans=INF;
for(i=0;i<=sum;i++)
if (f[i]>=psum/2)
{
ans=i;
break;
}
printf("%d/n",sum);
if (ans==INF) printf("impossible/n");
else printf("%d/n",ans);
}
return 0;
}