看题目戳我
题目大意:
有n个发电站,m条路,每条路有各自的距离,每个发电站有各自的发电量,现在需要炸毁它们,一辆坦克只能炸毁一个发电站,而且需要炸毁的发电厂的发电量需要大于所有发电站所产生的总电量的一半,求坦克走的最短距离。
题目思路:
看完这个题目一个比较容易产生的想法就是:求出源点到达其他点的最短距离,然后把距离从小到大排队,看到达哪个点(即哪个路线)炸毁的发电量可以达到要求。
下面比较明显的就是,想要求出源点到达每个其他点的距离,dijkstra当然是首选。
接下来就是如何判断这条路径能不能达到要求。
我们可以抽象出来(好吧也并不是很抽象),思路反一下,走这么长的距离最多可以炸毁多少发电量。这样是不是有点眼熟了呢?——跟背包问题有点像。把到每个点走的路长当作背包的体积,炸毁的发电量是每次可以装进去的价值。然后,bingo!
其他细节见代码
题目代码:
##include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#define maxn 10005
#define INF 0x3f3f3f3f
using namespace std;
int dis[105];
int f[80050];//dp用的
struct Edge
{
int u,v,w;
Edge(int uu,int vv,int ww):u(uu),v(vv),w(ww){}
};
struct Node
{
int id;
int w;
bool operator<(const Node &b)
const{w>b.w;}
}mid;
struct P
{
int po;
int d;
}poww[105];
vector<Edge>e[maxn];
priority_queue<Node>pq;
int cmp(P a,P b)
{
return a.d<b.d;
}
void dijk(int s)//dijkstra模板求出最短路
{
pq.push(Node{s,0});
dis[s]=0;
while(!pq.empty())
{
mid=pq.top();
pq.pop();
int card=mid.id;
if(mid.w!=dis[card])
continue;
for(int i=0;i<e[card].size();i++)
{
//printf("%d---%d----%d\n",card,dis[card],e[card][i].v);
if(dis[e[card][i].v]>dis[card]+e[card][i].w)
{
dis[e[card][i].v]=dis[card]+e[card][i].w;
pq.push(Node{e[card][i].v,dis[e[card][i].v]});
//printf("%d-----------------------%d\n",dis[card],e[card][i].w);
}
}
}
}
int main(void)
{
int t;
int n,m;
int a,b,c;
double tol;
scanf("%d",&t);
while(t--)
{
//cout<<0x3f3f3f3f<<endl;
scanf("%d%d",&n,&m);
memset(dis,0x3f,sizeof(dis));//初始化请注意
memset(f,0,sizeof(f));
memset(poww,0,sizeof(poww));
for(int i=0;i<=n;i++)
e[i].clear();
//
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
e[a].push_back(Edge{a,b,c});
e[b].push_back(Edge{b,a,c});
}
dijk(0);
//以上求出最短路
//print(n);
int sum=0;
int oil=0,p=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&poww[i].po);//价值
sum+=poww[i].po;
if(dis[i]<INF)
{
oil+=dis[i];
p++;
}
poww[i].d=dis[i];//体积
}
//print(n);
sort(poww+1,poww+n+1,cmp);
//可用油量为j的时候可以获得多少能量
for(int i=1;i<=p;i++)
{
for(int j=oil;j>=poww[i].d;j--)//注意如何把各个发电站的“体积”和“价值”对应起来,用P结构体
{
f[j]=max(f[j],f[j-poww[i].d]+poww[i].po);//依次获得相应油量下可以有多少价值
}
}
int i;
for(i=0;i<=oil;i++)
{
if(f[i]>=(sum/2+1))
break;
}
if(i<=oil)
printf("%d\n",i);
else
printf("impossible\n");
}
return 0;
}
/*
2
5 7
0 2 6
0 1 4
0 1 2
2 3 3
3 4 1
3 5 6
4 5 7
6 12 4 3 2
*/
呼呼