题意:
给出电站之间的路径长度和每个电站的电量,需要派出坦克去攻占电站,以控制多一半的电量(要比一半多,因为这个WA了一次),问最少走多少路径,坦克数量足够多,一个坦克只能控制一个电站。
思路:
用Floyd求出起点(0点)到所有电站的距离,当做背包物品的价值,然后以每个电站的发电量作为背包物品的容量,进行01背包。
然后找出背包容量在sumpow/2+1到10000(最大电量之和)的最小权值(路径总长)即为答案,若无,输出possible。
如果用路径长度当做物体体积,那么背包总容量太大了,这样做不合适。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N=105;
const int MAXV=10000;
const int INF=0x3F3F3F3F;
void work()
{
int dist[N][N];
int v[N];
int f[MAXV+5];
int i,j,k,x,y,l,n,m,sum,ans;
memset(dist,0x3F,sizeof(dist));
for(i=0;i<N;i++) dist[i][i]=0;
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&l);
if(l<dist[x][y])
dist[x][y]=dist[y][x]=l;
}
for(k=0;k<=n;k++)
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
if(dist[i][j]>dist[i][k]+dist[k][j])
dist[i][j]=dist[i][k]+dist[k][j];
v[0]=0;
sum=0;
for(i=1;i<=n;i++)
{
scanf("%d",&v[i]);
sum+=v[i];
}
memset(f,0x3f,sizeof(f));
f[0]=0;
for(i=1;i<=n;i++)
if(dist[0][i]<INF)
for(j=sum;j>=v[i];j--)
if(f[j]>f[j-v[i]]+dist[0][i])
f[j]=f[j-v[i]]+dist[0][i];
ans=INF;
for(i=sum/2+1;i<=MAXV;i++)
if(f[i]<ans) ans=f[i];
if(ans!=INF)
printf("%d\n",ans);
else printf("impossible\n");
}
int main()
{
int T;
scanf("%d",&T);
while(T--) work();
return 0;
}