PAT 1018 Public Bike Management (Dijkstra+dfs)

博客围绕杭州公共自行车服务,当站点非完美状态时需调整。给定站点容量、数量、问题站点及道路信息,要找出最小权值路径,输出发送和剩余车辆数。使用Dijkstra和dfs求解,因minSend和minBack不能简单求和传递,需存最短路并用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.

The above figure 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 S​3​​, we have 2 different shortest paths:

  1. PBMC -> S​1​​ -> S​3​​. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S​1​​ and then take 5 bikes to S​3​​, so that both stations will be in perfect conditions.

  2. PBMC -> S​2​​ -> S​3​​. 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.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 numbers: C​max​​ (≤100), always an even number, is the maximum capacity of each station; N (≤500), the total number of stations; S​p​​, 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 C​i​​ (i=1,⋯,N) where each C​i​​ is the current number of bikes at S​i​​ respectively. Then M lines follow, each contains 3 numbers: S​i​​, S​j​​, and T​ij​​ which describe the time T​ij​​ taken to move betwen stations S​i​​ and S​j​​. All the numbers in a line are separated by a space.

Output Specification:

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−>S​1​​−>⋯−>S​p​​. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of S​p​​ 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.

Sample Input:

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

Sample Output:

3 0->2->3 0

 

题目大意:自行车站的最大容量为Cmax,当自行车站的自行车数量为Cmax/2时,称该自行车站处于完美状态。当某个自行车站不是完美状态时,需要使其变为完美状态,从总部取出若干自行车发往目标站点,沿途的站点,若不为完美状态,也需要将他们调整为完美状态(若沿途站点的车辆数多于Cmax/2,则取走多余的车,若沿途站点的车辆数小于Cmax/2,则补充上少的车),现在给定自行车站的最大容量Cmax,和n个自行车站以及每个车站的自行车数量, 以及各个站点之间的权值,还有要更正为完美状态的车站号sp,求最小权值的路径,输出对应的发送车辆数minSend和剩余车辆数minBack,若最小权值路径有多条,那么输出其中需要从总部发送车辆数目最少 的路径,如果这样还有多条路径,那么则输出将sp修正成完美状态后剩余车辆数最少的路径。

 

思路:使用Dijkstra和dfs来求解最优路径。

使用Dijkstra求最短路题一般是这样的:

1.给定n个点,m条边,每条边的权值为w,然后给定一个出发点s和一个目的地t,求最短路径,直接套用Dijkstra即可

2.给定n个地点,m条路,每条路有距离和费用两个权值,然后给定一个出发点s和一个目的地t,求最短路径,若有多条最短路径,输出费用最少的那一条。

这时候要对Dijkstra中更新数据的部分进行修改

for(j=0;j<=n;j++)
        {
            if(!vis[j]&&dis[j]>dis[u]+mp[u][j])
            {
                dis[j]=dis[u]+mp[u][j];        //更新到j点的最短路径
                MinCost[j]=cost[u]+costMp[u][j];        //更新到j点的最小费用
            }
            else if(!vis[j]&&dis[j]==dis[u]+mp[u][j])
            {
            //路径长度相同时,查看是否需要更新最小费用
                if(MinCost[j]>cost[u]+costMp[u][j])    
                    {
                       MinCost[j]=cost[u]+costMp[u][j];    //更新到j点的最小费用
                    }
            }
        }

从s到t的最小花费时cost[t],最短路径长度为dis[t],之所以可以这样算的原因是:

Dijkstra是基于贪心的,Dijkstra能求出最优解,要求问题满足最优子结构条件。每次选出到s最近的点u,用u去更新s到其他点的距离,如果s通过u到某个点距离等于s直接到这个点的距离,那么在更新最小费用,最终求出最优路线(每个子问题最优后,全局问题也会最优)

本题不能只使用Dijkstra。因为minSend和minBack的值无法通过简单的求和来传递,就是说,选出来一个离s最近的点u,s通过u这个点到t的最短路径可以通过dis[u]+mp[u][t]来求和传递,但是s到t的minSend不等于s到u的minSend加上u到t的minSend,(因为u到t的minSend并不等于s到u的minBack,u到t的minSend考虑的是从u到t需要多少车才能使t以及沿线的车站达到完美状态)因此本问题,子结构最优并不能推出来全局最优,所以需要将最短路存起来,然后用dfs搜索每一条路径,最后记录最小minSend条件下最小minBack的路径

 

AC代码:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s,c;
int mp[510][510];   //存边
bool vis[510];      //标记数组
int dis[510];       //存距离
int num[510];       //存每个车站与完美状态车辆的差值
vector<int>MP[510];     //存最短路的图
vector<int>res,temp;    //存最终结果,temp是存过程中的遍历路径
int bookPath[510];      //dfs的标记数组
int min_bike=inf;       //最小发送车辆数
int min_back_bike=inf;  //最小返还车辆数

//最短路算法
void Dijkstra()
{
    int i,j;
    memset(dis,inf,sizeof(dis));
    dis[0]=0;
    for(i=0;i<=n;i++)
    {
        int minn=inf,u=-1;
        for(j=0;j<=n;j++)
        {
            if(!vis[j]&&dis[j]<minn)
            {
                minn=dis[j];
                u=j;
            }
        }
        vis[u]=true;
        for(j=0;j<=n;j++)
        {
            if(!vis[j]&&dis[j]>dis[u]+mp[u][j])
            {
                dis[j]=dis[u]+mp[u][j];
                MP[j].clear();      //更新最短路
                MP[j].push_back(u); //将最短路径上的点放入最短路图中
            }
            else if(!vis[j]&&dis[j]==dis[u]+mp[u][j])
            {
                MP[j].push_back(u);
            }
        }
    }
    return ;
}
void dfs(int i)
{
    temp.push_back(i);  //将当前节点存入数组
    if(i==0)
    {
        int need=0,back=0;
        for(int j = temp.size()-1;j>=0;j--)
        {
            int id = temp[j];
            if(num[id]>0)
            {
                back+=num[id];
            }
            else
            {
                if(back>(-num[id]))
                {
                    back+=num[id];
                }
                else
                {
                    need+=-num[id]-back;
                    back=0;
                }
            }
        }
        if(min_bike>need)
        {
            min_bike=need;
            min_back_bike=back;
            res=temp;
        }
        else if(min_bike==need&&min_back_bike>back)
        {
            min_back_bike=back;
            res=temp;
        }
        temp.pop_back();
        return ;
    }
    for(int j = 0;j<MP[i].size();j++)
    {
        if(!bookPath[MP[i][j]])
        {
            bookPath[MP[i][j]]=1;
            dfs(MP[i][j]);
            bookPath[MP[i][j]]=0;
        }
            
    }
    temp.pop_back();        //将当前节点从数组中取出
}
int main()
{
    int i,j,x;
    cin>>c>>n>>s>>m;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&x);
        /*存差值,在dfs遍历时候,把从终止节点到0节点路径上的点的差值加起来
        如果最后的总和为负数,则说明需要发送车辆,返还车辆为0;若为正数,那
        么不需要发送车辆,返回车辆数不为0,这样大大方便了枚举最优路线
        */
        num[i]=x-c/2;       
    }
    memset(mp,inf,sizeof(mp));
    int u,v,w;
    for(i=1;i<=m;i++)
    {
        scanf("%d %d %d",&u,&v,&w);
        mp[u][v]=mp[v][u]=w;
    }
    
    Dijkstra();
    dfs(s);
    cout<<min_bike<<" "<<0;
    for(i=res.size()-2;i>=0;i--)
    {
        printf("->%d",res[i]);
    }
    cout<<" "<<min_back_bike<<endl;
    return 0;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值