zoukankan      html  css  js  c++  java
  • Public Bike Management (30) (Dijkstra路径保存fa[]+DFS)

    题目描述

    There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world.  One may rent a bike at any station and return it to any other stations in the city.
    The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
    When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.

    Figure 1
    Figure 1 illustrates an example.  The stations are represented by vertices and the roads correspond to the edges.  The number on an edge is the time taken to reach one end station from another.  The number written inside a vertex S is the current number of bikes stored at S.  Given that the maximum capacity of each station is 10.  To solve the problem at S3, we have 2 different shortest paths:
    1. PBMC -> S1 -> S3. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1 and then take 5 bikes to S3, so that both stations will be in perfect conditions.
    2. PBMC -> S2 -> S3. This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.
    
    

    输入描述:

    Each input file contains one test case.  For each case, the first line contains 4 numbers: Cmax (<= 100), always an even number, is the maximum capacity of each station; N (<= 500), the total number of stations; Sp, the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads.  The second line contains N non-negative numbers Ci (i=1,...N) where each  Ci is the current number of bikes at Si respectively.  Then M lines follow, each contains 3 numbers: Si, Sj, and Tij which describe the time Tij taken to move betwen stations Si and Sj.  All the numbers in a line are separated by a space.


    输出描述:

    For each test case, print your results in one line.  First output the number of bikes that PBMC must send.  Then after one space, output the path in the format: 0->S1->...->Sp.  Finally after another space, output the number of bikes that we must take back to PBMC after the condition of Sp is adjusted to perfect.
    Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge's data guarantee that such a path is unique.
    
    

    输入例子:

    10 3 3 5
    6 7 0
    0 1 1
    0 2 1
    0 3 3
    1 3 1
    2 3 1
    
    

    输出例子:

    3 0->2->3 0
    发出的自行车数;路径;收回的自行车数;

    题目大意:

    一个无向图,有N个节点,有N-1个(自行车)站点,编号为0的点时自行车总部PBMC,每个站点可容纳的自行车数最大是Cmax,边的权值Tij表示序号ij两站之间需要花费的时间,
    对于一个站点,如果自行车数为零或者满了,都属于问题车站,现给出图中一个问题车站序号Sp,求出总部到Sp的最短路径(时间最短),并且使得途径的每一个站的自行车数都
    变得完美(即自行车数都为Cmax/2)。当有多条最短路时,找到使得总部需要发出自行车数最少的路径。


    解题思路:

    求最短路用Dijkstra,并且记录每个节点的上一个路径信息(可能有多个)。

    DFS遍历每条路径,并且将路径写入栈中(栈path将作为DFS函数的参数!!!)

      理解DFS中sum,maxx,minn的用法:这里先假设到Sp点后自行车刚好全部放完(即收回0辆),

    以此来推测前面节点时应该携带的自行车数。再根据携带自行车数不能小于0,即sum>=0求出最终的发出收回自行车数

    ps:path作为DFS的参数,就可以实现路径信息记录与路径的遍历同步更新。

    pps:Dijkstra访问的下一个点:必须是未被访问过的点中d值最小的,即最近的点。

    代码:

    /***********************************************/
    int Cmax,N,Sp,M;
    int c[550];//每个站点当前自行车数 
    int d[550];//每个节点到原点0的最短距离
    bool B[550];//标记 
    int NN=1;//路径总数 
    
    vector<int>fa[550];//父指针 ,可能是多个 
     
    struct node{
        int v;
        int edge;//边长 
        node(){}
        node(int _v,int _e):v(_v),edge(_e){}
    };
    vector<node>G[550];//领接表 
    
    int select_min()
    {
        int t=inf;
        int ans;
        for(int i=0;i<=N;i++){
            if(B[i]==1) continue;
            if(d[i]<t){
                t=d[i];
                ans=i;
            }
        }
        return ans;
    }
    void Dijkstra()
    {
        for(int i=0;i<=N;i++) d[i]=(i==0?0:inf);
        for(int i=0;i<=N;i++){
            //选出未访问节点中d最小的
            int y=select_min(); 
            B[y]=1;
            for(int j=0;j<G[y].size();j++){
                if(d[G[y][j].v]>(d[y]+G[y][j].edge)) {
                    d[G[y][j].v]=d[y]+G[y][j].edge;
                    fa[G[y][j].v].clear();
                    fa[G[y][j].v].push_back(y);
                }
                else if(d[G[y][j].v]==(d[y]+G[y][j].edge)) {
                    fa[G[y][j].v].push_back(y);
                }
            }
        }
        //统计有几条路径分支
        for(int i=1;i<=N;i++){
            if(fa[i].size()>1) NN*=fa[i].size();
        }
    }
    
    vector< stack<int> > V;
    int ANS1=inf,ANS2=0;
    void DFS(int now,int sum,int maxx,int minn,stack<int> path)
    {
        path.push(now);
        if(now==0) {
            int ans1=0,ans2=0;
            if(minn<0){
                sum-=minn;
                ans1=sum;
                ans2-=minn;
            }
            else{
                ans2=0;
                ans1=sum;
            }
            
            if(ans1<ANS1){
                ANS1=ans1;    ANS2=ans2;
                V.clear();V.push_back(path);
            }
            return ;
        }
        sum+=(Cmax/2-c[now]);
        maxx=max(maxx,sum);
        minn=min(minn,sum);
        
        for(int i=0;i<fa[now].size();i++)
        {
            DFS(fa[now][i],sum,maxx,minn,path);
        }
        
    }
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        cin>>Cmax>>N>>Sp>>M;
        for(int i=1;i<=N;i++) cin>>c[i];
        int Si,Sj,Tij;
        for(int i=1;i<=M;i++)
        {
            cin>>Si>>Sj>>Tij;
            G[Si].push_back(node(Sj,Tij));
            G[Sj].push_back(node(Si,Tij));
        }
        Dijkstra();
        
        stack<int>st;//保存路径信息 
        DFS(Sp,0,0,0,st);
        
        
        cout<<ANS1<<" ";
        while(V[0].size()>1){
            cout<<V[0].top()<<"->";    
            V[0].pop();
        }
        cout<<V[0].top()<<" ";
        cout<<ANS2<<endl;
        return 0;
    }
    原版
    ***********************************************/
    int Cmax,N,Sp,M;
    int c[550];//每个站点当前自行车数 
    int d[550];//每个节点到原点0的最短距离
    bool B[550];//标记 
    int NN=1;//路径总数 
    
    vector<int>fa[550];//父指针 ,可能是多个 
     
    struct node{
        int v;
        int edge;//边长 
        node(){}
        node(int _v,int _e):v(_v),edge(_e){}
    };
    vector<node>G[550];//领接表 
    
    struct Heapnode{
        int d;//最短距离 
        int num;//节点序号 
        bool operator < (const Heapnode& rhs) const{
            return d>rhs.d;
        }
    };
    
    void Dijkstra()
    {
        priority_queue<Heapnode> Q;//优先队列 
        for(int i=0;i<=N;i++) d[i]=(i==0?0:inf);
        Q.push((Heapnode){0,0});//开始时待选择的点只有原点 
        while(!Q.empty())
        {
            Heapnode x=Q.top();    Q.pop();
            if(B[x.num]) continue;//避免重复访问 
            B[x.num]=1;
            for(int i=0;i<G[x.num].size();i++)//松弛操作 
            {
                if(d[G[x.num][i].v]>(d[x.num]+G[x.num][i].edge)){
                    d[G[x.num][i].v]=(d[x.num]+G[x.num][i].edge);
                    fa[G[x.num][i].v].clear();
                    fa[G[x.num][i].v].push_back(x.num);
                }
                else if(d[G[x.num][i].v]==(d[x.num]+G[x.num][i].edge)){
                    fa[G[x.num][i].v].push_back(x.num);
                }
                
                Q.push((Heapnode){d[G[x.num][i].v],G[x.num][i].v});
            }
        }
    }
    
    vector< stack<int> > V;
    int ANS1=inf,ANS2=0;
    void DFS(int now,int sum,int maxx,int minn,stack<int> path)
    {
        path.push(now);
        if(now==0) {
            int ans1=0,ans2=0;
            if(minn<0){
                sum-=minn;
                ans1=sum;
                ans2-=minn;
            }
            else{
                ans2=0;
                ans1=sum;
            }
            
            if(ans1<ANS1){
                ANS1=ans1;    ANS2=ans2;
                V.clear();V.push_back(path);
            }
            return ;
        }
        sum+=(Cmax/2-c[now]);
        maxx=max(maxx,sum);
        minn=min(minn,sum);
        
        for(int i=0;i<fa[now].size();i++)
        {
            DFS(fa[now][i],sum,maxx,minn,path);
        }
        
    }
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        cin>>Cmax>>N>>Sp>>M;
        for(int i=1;i<=N;i++) cin>>c[i];
        int Si,Sj,Tij;
        for(int i=1;i<=M;i++)
        {
            cin>>Si>>Sj>>Tij;
            G[Si].push_back(node(Sj,Tij));
            G[Sj].push_back(node(Si,Tij));
        }
        Dijkstra();
        
        stack<int>st;//保存路径信息 
        DFS(Sp,0,0,0,st);
        
        
        cout<<ANS1<<" ";
        while(V[0].size()>1){
            cout<<V[0].top()<<"->";    
            V[0].pop();
        }
        cout<<V[0].top()<<" ";
        cout<<ANS2<<endl;
        return 0;
    }
    优先队列优化版

    参考博客:1018. Public Bike Management (30)-PAT甲级真题(Dijkstra + DFS)

    例题2:Til the Cows Come Home

    自家传送门->>>>>>https://www.cnblogs.com/liuyongliu/p/11206332.html

  • 相关阅读:
    关于模式窗体的缓存问题的解决方案
    C# 读取网页
    C# 压缩文件
    C#实现反射调用动态加载的DLL文件中的方法
    在线程中修改窗体控件内容
    C# 启用双缓存,避免ListView控件加载数据时闪烁
    JBuilder2005破解方法
    C# combbox datatable 赋值
    今天感觉到秋凉了~
    烦人的流程图~~~
  • 原文地址:https://www.cnblogs.com/liuyongliu/p/11201861.html
Copyright © 2011-2022 走看看