简述题意:
给出N个供电站编号从1~N,然后给出M条边:并且给出这N个供电站的电量。每辆坦克从基地出发去攻击供电站,并且每辆坦克只能攻击一个供电站,求要使的破坏总电量的一半以上,求这些坦克要走的最短距离。
难度:NOIP
算法:首先,从基地跑一次最短路,求出到所有供电站的距离,接下来就是01背包了!
所有供电站的电量总和为->背包容量
每个供电站为->背包中的物品
每个供电站的电量为->背包中物品的代价
基地到每个供电站的距离为->背包中物品的价值
所以,记得清数组,判无解。
代码如下:
#include <bits/stdc++.h>
#define ll long long
#define N 10005
using namespace std;
struct node
{
int next;
int to;
int val;
}edg[N<<1];
int hea[N],cnt=1;
int vis[N],dis[N];
void init()
{
memset(hea,-1,sizeof(hea));
memset(vis,0,sizeof(vis));
cnt=1;
}
void add(int u,int v,int w)
{
edg[cnt].next=hea[u];
edg[cnt].to=v;
edg[cnt].val=w;
hea[u]=cnt++;
}
struct no
{
int d;
int po;
};
bool operator < (no x,no y)
{
return x.d>y.d;
}
void dijkstra(int rt)
{
memset(dis,0x3f3f3f3f,sizeof(dis));
priority_queue<no>Q;
no tem;
tem.d=0;
tem.po=rt;
dis[rt]=0;
Q.push(tem);
while(!Q.empty())
{
no tt=Q.top();
Q.pop();
int u=tt.po;
if(vis[u]) continue;
vis[u]=1;
for(int i = hea[u];i != -1;i=edg[i].next)
{
int to=edg[i].to;
if(dis[to]>dis[u]+edg[i].val)
{
dis[to]=dis[u]+edg[i].val;
no point;
point.po=to;
point.d=dis[to];
Q.push(point);
}
}
}
}
int aa[150];
int dp[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
init();
for(int i = 1;i <= m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a+1,b+1,c),add(b+1,a+1,c);
}
int sum=0;
for(int i = 1;i <= n;i++)
{
scanf("%d",&aa[i]);
sum+=aa[i];
}
dijkstra(1);
int ans=0x3f3f3f3f;
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[0] = 0;
for(int i = 1;i <= n;i++)
{
for(int j = sum;j >= aa[i];j--)
{
dp[j]=min(dp[j],dp[j-aa[i]]+dis[i+1]);
}
}
for(int i = sum/2+1;i <= sum;i++)
{
ans=min(ans,dp[i]);
}
if(ans==0x3f3f3f3f) puts("impossible");
else printf("%d\n",ans);
}
return 0 ;
}