1018 Public Bike Management

题意:假设一个站点可容纳Capacity辆自行车(c确保为偶数),则恰有c/2辆时为完美状态。若某站点当前自行车数量为满,管理中心就会前往该站点进行回收;若当前数量为0,则管理中心就会向该站点派发自行车。需要注意的是,由管理中心到站点Sp沿路的所有站点在去的途中就会被调整至完美状态(“all the stations on the way will be adjusted as well.”)。当问题站点Sp发出调整请求后,管理中心会选择耗时最短的一条路径;若有多条最短路径,则选择需要派发车辆最少的那一条。若仍然有多条路径,则选择需要带回管理中心的自行车数量最少的路径。

思路:本题采用Dijkstra+DFS的思路来做。Dijkstra只负责求出最短路径,以及记录最短路径中结点的前驱。更新派发车辆send以及带回的车辆remain在DFS中完成。求最短路就不用赘述了,套模板,下面讲一下如何求最优解。

我们令send表示需要从PBMC发出的自行车数量,初始化为0。即沿途中若有站点的自行车数量小于c/2的,就需要从PBMC中派发,遍历过程中一直累加;令remain表示在处理当前站点i之前,处理完[1~i-1]个站点后余留下来的数量,其值要么为0,要么大于0,初始化也为0。每访问一个站点i时,考虑此前余留的数量remain+该站点的数量是否达到完美状态,即remain+bike[i]与c/2的大小关系,若remain+bike[i]<c/2,说明需要从管理中心额外再派发,因此send要累加,即send+=c/2-(remain+bike[i]),并同时更新remain=0(没得剩了嘛);若remain+bike[i]>=c/2时,说明处理完这个站点后,自行车数量还有的多(即若有需要,可以增补给后面的站点),因此更新remain=remain+bike[i]-c/2,send则不需要处理。

代码:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int Inf=0x7fffffff;
const int maxn=510;
struct Node{
    int v;
    int t;
    Node(int v_,int t_):v(v_),t(t_){}
};
vector<Node> Adj[maxn];
vector<int> pre[maxn];
bool vis[maxn];
int mindis[maxn];
int bike[maxn];
int c,n,sp,m;

void Dijkstra(int s)
{
    fill(vis,vis+maxn,false);
    fill(mindis,mindis+maxn,Inf);
    mindis[s]=0;

    for(int k=0;k<=n;k++){
        int u=-1,min=Inf;
        for(int v=0;v<=n;v++){
            if(!vis[v] && mindis[v]<min){
                min=mindis[v];
                u=v;
            }
        }
        if(u==-1) return;
        vis[u]=true;

        //relax:松弛操作
        for(auto node:Adj[u]){//u-v
            if(!vis[node.v]){
                if(mindis[u]+node.t < mindis[node.v]){
                    mindis[node.v]=mindis[u]+node.t;
                    pre[node.v].clear();
                    pre[node.v].push_back(u);
                }else if(mindis[u]+node.t == mindis[node.v]){
                    pre[node.v].push_back(u);
                }
            }
        }
    }
}

//打印路径
vector<int> path,tmp;
int minSend=Inf, minRemain=Inf;
void dfs(int v)
{
    tmp.push_back(v);
    if(v==0){//起点固定为0
        int perfect=c/2;
        int remain=0,send=0;
        for(auto it=tmp.rbegin()+1;it!=tmp.rend();it++){//路径中的首个结点是PBMC,它不参与计算
            if(remain+bike[*it] < perfect){
                send += perfect-(remain+bike[*it]);
                remain = 0;
            }else if(remain+bike[*it] >= perfect){
                remain = remain+bike[*it]-perfect;
            }
        }
        if(send<minSend){
            minSend=send;
            minRemain=remain;
            path=tmp;
        }else if(send==minSend && remain<minRemain){
            minRemain=remain;
            path=tmp;
        }
        return;
    }
    for(auto p:pre[v]){
        dfs(p);
        tmp.pop_back();
    }
}

int main()
{
    //freopen("pat.txt","r",stdin);
    scanf("%d%d%d%d",&c,&n,&sp,&m);
    for(int i=1;i<=n;i++) scanf("%d",&bike[i]);
    int u,v,t;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&u,&v,&t);
        Adj[u].push_back(Node(v,t));
        Adj[v].push_back(Node(u,t));
    }
    Dijkstra(0);
    dfs(sp);
    printf("%d ",minSend);
    for(int i=path.size()-1;i>=0;i--){
        printf("%d",path[i]);
        if(i>0) printf("->");
    }
    printf(" %d\n",minRemain);
    return 0;
}

 

转载于:https://www.cnblogs.com/kkmjy/p/9591586.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值