题意
给定一个无向图代表一个电网
n
n
个节点 条边,每个节点上都有一个电站,每个电站都有一个功率,每条边上都有一个价值。现在在节点
0
0
上(不属于那 各节点),有无数辆坦克可以开到一个电站并将它关闭(关闭后坦克不能移动)。求关闭一半以上的功率至少需要多少价值。
1≤n≤100
1
≤
n
≤
100
1≤m≤10000
1
≤
m
≤
10000
思路
最短路径与01背包的结合,将从 0 0 节点到其他节点的最短路长度看作物品的体积,将每个电站的功率看作它的价值。跑一遍 01背包再扫一遍 数组找到最优解即可。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
using namespace std;
struct Pack
{
int V;
int dp[10003];
Pack(int _){V=_;memset(dp,0,sizeof(dp));}
void ZeroOne_load(int v,int p)
{
DOR(i,V,v)dp[i]=max(dp[i],dp[i-v]+p);
return;
}
};
struct node
{
int at,path;
bool operator<(const node &_)const
{
return path>_.path;
}
};
struct edge
{
int to,cost;
};
struct dijkstra
{
int dis[103],n;
vector<edge>E[103];
dijkstra(int _)
{
n=_;
memset(dis,63,sizeof(dis));
FOR(i,1,n)E[i].clear();
}
void add(int u,int v,int w)
{
E[u].push_back((edge){v,w});
return;
}
void solve(int s)
{
dis[s]=0;
priority_queue<node>q;
while(!q.empty())q.pop();
q.push((node){s,0});
while(!q.empty())
{
node now=q.top();q.pop();
int u=now.at;
if(dis[u]<now.path)continue;
FOR(i,0,(int)E[u].size()-1)
{
int v=E[u][i].to,w=E[u][i].cost;
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
q.push((node){v,dis[v]});
}
}
}
return;
}
int go(int v){return dis[v];}
};
int main()
{
int T,n,m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
dijkstra SP(n);
FOR(i,1,m)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
SP.add(u,v,w);SP.add(v,u,w);
}
SP.solve(0);
Pack P(10000);
int tot=0;
FOR(i,1,n)
{
int c;
scanf("%d",&c);
tot+=c;
P.ZeroOne_load(SP.go(i),c);
}
bool flag=0;
FOR(i,0,P.V)
{
if(P.dp[i]>tot/2)
{
printf("%d\n",i);
flag=1;
break;
}
}
if(!flag)printf("impossible\n");
}
return 0;
}