hdu 4318 最短路问题

比赛没写出来耻辱啊!又看了看邻接表,懂了之后写的。当时因为是50001个数据,如果临街矩阵的话肯定mle,只能用到邻接表,我当时邻接表不是很熟,觉得写不出来就没有写


题意:大致表述为从节点s向节点t传送电力,电力在传送过程中会有所消耗,不同节点之间,电力传送消耗的值有所不同。要求选择一条使得电力消耗最小的线路。如果不能把电力从s点传送到t点,或者电力损失殆尽,则输出IMPOSSIBLE!

如果从s出发,没有到达t的路径,则输出IMPOSSIBLE!
如果存在这样一条路径p = (s,p1,p2,p3,…,pn,t),那么最后到达t的电力为M*(1-b1%)*(1-b2%)*…*(1-bn%)*(1-bn+1%)。即我们需要找到这样一条路径,使得(1-b1%)*(1-b2%)*…*(1-bn%)*(1-bn+1%)最大。

思路:

思路1、我们可以把乘积的形式通过取对数化作连续相加的形式

即log(1-b1%) +…+log(1-bn+1%),由于 log(1-bi%)都是小于0的,我们要求这个式子的最大值就是求每个子式取绝对值的最小值。所以通过取对数在取绝对值的操作,我们可以得到两节点之间新的边权。同时题目也转化为求单源最短路问题。最后注意把结果进行转化。

思路2、直接贪心。类似于Dijkstra算法。我们要求损耗最小,也就是剩余最大。对于每个节点,我们记录起当前可以达到的剩余最大电力。和Dijkstra算法相似,我们这里每次找寻的是尚未标记的拥有最大值的结点,并把这个最大值作为当前结点的最终结果,标记此结点并通过当前结点拓展与之相连的结点。因为从一个结点传输电力到另一个几点,电力的总量是不会增加的。所以,在以后的贪心过程中,不会更新之前已经标记的结点,因为不可能有更大的值。
这样只要求得最后到达t的最大剩余电力就能得出答案。

 

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
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int nv=50006;
const int ne=2505010;
#define data 100000000
int n;
double M;
struct Dijkstra
{
    int nn,size;
    double dis[nv];
    int mark[nv],head[nv];

    struct edge{
        int v,next;
        double w;
        edge(){}
        edge(int v,int next,double w):v(v),next(next),w(w){}
    }ee[ne];

    inline void init(int nx)
    {
        nn=nx;size=0;
        memset(head,-1,sizeof(head));

    }
    inline void insert(int u,int v,double w)
    {
        ee[size]=edge(v,head[u],w);
        head[u]=size++;
    }

    void spfa(int src,int n)
    {
        memset(mark,0,sizeof(mark));
        queue<int>q;
        for(int i=1;i<=n;i++)
        {
            dis[i]=data;
        }
        dis[src]=0;
        q.push(src);
        mark[src]=true;
        while(!q.empty())
        {
             int uu=q.front();
             q.pop();
             mark[uu]=0;
             for(int i=head[uu];i!=-1;i=ee[i].next)
             {
                 int v=ee[i].v;
                 if(dis[v] > dis[uu]+(M-dis[uu])*((double)ee[i].w/100))//跟最短路的思想差不多,不断松弛dis[],当下个节点的消耗量小于上个节点时就更新                 
                 {
                     dis[v] =dis[uu]+(M-dis[uu])*((double)ee[i].w/100);
                     if(!mark[v])
                     {
                        q.push(v);
                        mark[v]=1;
                     }
                     
                 }
             }
        }
        return ;
    }
}g;
int main()
{
    int m,destination,start,end,weight;
    while(scanf("%d",&n)!=EOF)
    {
       g.init(n);
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&m);
           while(m--)
           {
               scanf("%d%d",&destination,&weight);
               g.insert(i,destination,weight);
           }
       }
       scanf("%d%d%lf",&start,&end,&M);
       g.spfa(start,n);
       if(g.dis[end]<data)
       printf("%.2lf\n",g.dis[end]);
       else
       printf("IMPOSSIBLE!\n");
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值