pat 甲级 1018 Public Bike Management

文章讲述了如何结合Dijkstra算法和DFS遍历来解决PBMC中自行车分配的问题,以找到满足节点完美需求的最小自行车发送和带回策略。
摘要由CSDN通过智能技术生成

这道题的主要方法是Dijkstra+DFS。首先利用Dijkstra算法找出原点到目标p点的所有最短路径,然后利用dfs遍历所有的最短路径,更新send跟bring;

1.Dijkstra()算法的模板:

void dijkstra(){
    memset(dist,0x3f,sizeof dist);//使所有到目标p点的距离初始化为无穷大
    dist[p]=0;//p到自身的距离为0
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=0;j<=n;j++){//找出没有遍历过且距离p点最近的点
            if(!st[j]&&(t==-1||dist[j]<dist[t]))
                t=j;
        }
        st[t]=true;//标记
        for(int j=0;j<=n;j++){//更新与t相关的节点
            dist[j]=min(dist[j],dist[t]+d[t][j]);
        }
    }
}

2.send(PBMC需要发出的自行车数量)如何在满足要求下保证最小,可以send初始为0,DFS遍历所有最短路径,当节点不完美时,send-(最大数量/2-节点bike的数量)即需要满足perfect所需的bike数目的负值。则send的值为abs(最小的负数)。而带回来的bike数量则是发出的自行车数量-路径满足perfect所需的bike数量。

同时注意DFS更新答案的优先级如下:

(1)路径取得最小值  (Dijkstra()已经实现)

(2)在(1)都满足的条件下,PBMC发出的bike需要最小

(3)在(1)(2)都满足的条件下,带回来的bike需要最小;

代码实现:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>

using namespace std;
const int N=510;
int w[N];//每个station的bike
int d[N][N];//station之间的时间
int dist[N];//每个station到达目标station的最短路径
int cmax,n,m,p;
int send=0x3f3f3f,bring=0x3f3f3f;//send为PBMC要发出的bike,bring是带回来的bike,初始化为无穷大
bool st[N];//标记是否访问过
vector<int> ans,path;
void dijkstra(){
    memset(dist,0x3f,sizeof dist);
    dist[p]=0;
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=0;j<=n;j++){
            if(!st[j]&&(t==-1||dist[j]<dist[t]))
                t=j;
        }
        st[t]=true;
        for(int j=0;j<=n;j++){
            dist[j]=min(dist[j],dist[t]+d[t][j]);
        }
    }
}
/*(1)路径取得最小值

(2)在(1)都满足的条件下,PBMC发出的bike需要最小

(3)在(1)(2)都满足的条件下,带回来的bike需要最小;*/
void dfs(int u,int s,int mins){
    if(u){
        s-=cmax/2-w[u];//station变成perfect所需的bike
        mins=min(s,mins);//取最小的负数
    }
    if (u==p)
    {
        int sd=abs(min(mins,0));//mins是路径上所有station变成perfect所需的bike的最小的负数,即send的负数,故send=abs(mins)若大于0,则不需要发出bike,故取0。send=abs(min(mins,0));
        int bg=s+sd;
        if(sd<send) ans=path,send = sd,bring = bg; //该条路径下比其他最短路径PBMC所需要发出的bike更少,即满足(2)替换答案;
        else if(sd==send&&bg<bring) ans =path,bring=bg;//满足(3)的情况
        return;
    }
    for (int i = 1; i <= n; i ++ )
        if (dist[u] ==d[u][i] + dist[i])//u->i 当u到目标p点的最短距离等于u带i的距离+i到目标p点的最短距离,则i是最短路径上的节点
        {
            path.push_back(i);
            dfs(i,s,mins);
            path.pop_back();//回溯
        }
}
int main()
{
    
    cin>>cmax>>n>>p>>m;
    for(int i=1;i<=n;i++) cin>>w[i];
    memset(d,0x3f,sizeof d);
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        d[a][b]=d[b][a]=min(d[a][b],c);//无向图可以看出有两条边的有向图,所以d[a][b]=d[b][a],min(d[a][b],c)是防止有重边的题目,可写可不写
    }
    dijkstra();
    path.push_back(0);//路径的起始点0
    dfs(0,0,0);//遍历所有可能的最短路径
    cout<<send<<" "<<0;
    for (int i=1;i<ans.size();i ++ )
        cout<<"->"<<ans[i];
    cout << " " <<bring << endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值