Hdoj4318 hdu4318

Problem Description
The project West-East power transmission is famous around the world. It transmits the electricity from western areas to east China. There are many nodes in the power system. Each node is connected with several other nodes in the system by cable. Power can be only transmitted between two connected nodes. For each node, it can’t send power to two or more other nodes at the same time. 
As we have all known, power will be loss during the transmission. Bob is the chief engineer of the project. He wants to build a transmission line which send power from one node to another node and minimize the power loss at the same time. Now he asks you to help him solve the problem.
 

Input
There are several test cases. For each test case, the first line contains an integer N (0 < N ≤ 50000) which represents the number of nodes in the power system. Then there will be N groups of data following. For the i-th(0 < i ≤ N) group, the first line is an integer ki (ki ≤ 50), which means the node i is connected with ki nodes. The rest of the i-th group data are divided into ki lines. Each line contains an integer ai (0 < ai ≤ N, ai ≠ i) and an integer bi (0 ≤ bi ≤ 100), which represents power can be transmitted from node i to ai and will loss bi% while transmitting. The last line of input data contains three integers separated by single spaces. The first one is s, the second is t (0 < s, t ≤ N), and the third is the total power M (0 < M ≤ 10^6) at node s.
 

Output
For each test case, output the minimum of loss power while transmitting from node s to node t. The result should be printed with two digits to the right of the decimal point. If power cannot be transmitted from node s to node t, output “IMPOSSIBLE!” in a line.
 

Sample Input
  
  
4 2 2 50 3 70 2 1 30 4 20 2 1 10 4 40 0 1 4 100
 

Sample Output
  
  
60.00
Hint
In the sample, the best transmission line is 1 -> 2 -> 4, loss power is 100 * 50% + 100 * (100%-50%)*20% = 60.00
题意:
有个发电站,它给你value点电量,发电站建在s处,我们要运送到t处,每条路会损耗电量,问最少损耗多少电量?!
分析:
走1->3->2->4->5走1->2->4->5
初始时1能量100初始时1能量100
1->3耗能201->2耗能50
剩余能量80剩余能量50
3->2耗能82->4耗能25
剩余能量72剩余能量25
2->4耗能364->5耗能12.5
剩余能量36剩余能量12.5
4->5耗能18分析后可知1->2走1-3->2耗能少
剩余能量18
根据初步观察,这是一道最短路问题,我们假设要从1走到5。初始的电量为100,便于计算。
如上图,1->3消耗20%,3->2消耗10%,则到2的时候消耗了28点电量,如果从1->2消耗50点电量,那么果断走1->3->2啊!,后面无论如何这就是最小的消耗路线!
然后我们进行分析,这里采用spfa显然可以,有5W个点,5W*50条边,那么spfa的松弛操作是这题的关键。
如我们所学的基础的松弛操作为:
if(dis[v]>dis[u]+a[i].w)//a[i].w是从u->v这条边的权值
dis[v]=dis[u]+a[i].w
而这道题中我们要把消耗的百分比当成边的权值,并且记录下改点剩余的电量,松弛的时候进行两个操作
if(dis[v]>dis[u]+a[i].w*val[u])//val[u]为剩余电量
{
dis[v]=dis[u]+ a[i].w*val[u];
val[v]=val[u]*(1-a[i].w)//该点剩余电量是上一个点的剩余电量减去损耗的电量
}
把这个松弛操作替换spfa中的松弛,我们就能很快的a掉这题了!
code:
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define path 2500005//边数:50000*50以上
#define N 50005//点数
queue <int>mm;
struct s{
	int to,next;
	double w;//w是每条边的权值,因为是百分比,所以用double存
}a[path];
int eid,p[path],value,cov[N];//value是初始电量,cov存的是点是否在队列中
double val[N],dis[N];//val存的是改点剩余电量,dis存的是从初始点到该点消耗的最小电量(即s->i的最小消耗)
void init()
{
	memset(p,-1,sizeof(p));
	eid=0;
	int i;
	for(i=0;i<N;i++){
		dis[i]=1<<30;
		val[i]=-1;
	}
}
void ljb(int from,int to,double w)
{
	a[eid].to=to;
	a[eid].w=w;
	a[eid].next=p[from];
	p[from]=eid++;
}
void spfa(int s)
{
	int u,v,i;
	while(!mm.empty())
		mm.pop();
	mm.push(s);
	memset(cov,0,sizeof(cov));
	cov[s]=1;
	dis[s]=0;
	val[s]=value;
	while(!mm.empty())
	{
		u=mm.front();
		mm.pop();
		cov[u]=0;
		for(i=p[u];i!=-1;i=a[i].next)
		{
			v=a[i].to;
			if(dis[v]>dis[u]+val[u]*a[i].w){//松弛操作的更改
				dis[v]=dis[u]+val[u]*a[i].w;
				val[v]=val[u]*(1-a[i].w);
				if(!cov[v]){
					cov[v]=1;
					mm.push(v);
				}
			}
		}
	}
}
int main()
{
	int n,i,m,x,w,s,t;
	while(~scanf("%d",&n))
	{
		init();
		for(i=1;i<=n;i++){
			scanf("%d",&m);
			while(m--){
				scanf("%d%d",&x,&w);
				ljb(i,x,w*1.0/100);
			}
		}
		scanf("%d%d%d",&s,&t,&value);
		spfa(s);
		if(dis[t]==1<<30)
			printf("IMPOSSIBLE!\n");
		else
			printf("%.2f\n",dis[t]);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值