我的笔记之A1018 Public Bike Management⭐

题意

每个自行车车站的最大容量为一个偶数cmax,如果一个车站里面自行车的数量恰好为cmax / 2,那么称处于完美状态。如果一个车站容量是满的或者空的,控制中心(处于结点0处)就会携带或者从路上收集一定数量的自行车前往该车站,一路上会让所有的车站沿途都达到完美。现在给出cmax,车站的数量n,问题车站sp,m条边,还有距离,求最短路径。如果最短路径有多个,求能带的最少的自行车数目的那条。如果还是有很多条不同的路,那么就找一个从车站带回的自行车数目最少的(带回的时候是不调整的)

思路

Dijkstra + DFS。如果只有Dijkstra是不可以的,因为minNeed和minBack在路径上的传递不满足最优子结构,不是简单的相加的过程,只有在所有路径都确定了之后才能区选择最小的need和最小的back~
Dijkstra求最短路径,dfs求minNeed和minBack和path,dfs的时候模拟一遍需要调整的过程,求出最后得到的need和back,与minNeed和minBack比较然后根据情况更新path,最后输出minNeed path 和 minBack,记得path是从最后一个结点一直到第一个结点的,所以要倒着输出

AC代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

const int INF = 999999999;

bool visit[505] = {false};
int weight[505];
int dis[505];
int e[505][505];
vector<int> pre[505];
int c,n,p,m;

int minNeed=INF,minBack=INF;
vector<int> tmp,final;

void dfs(int index){
    tmp.push_back(index);
    if(index==0){
        int need=0,back=0;
        for(int i=tmp.size()-1;i>=0;i--){
            int id = tmp[i];
            if(weight[id]>0)
                back+=weight[id];
            else{
                if(back>(-weight[id]))
                    back+=weight[id];
                else{
                    need+=(-weight[id])-back;
                    back=0;
                }
            }
        }
        if(need<minNeed){
            minNeed = need;
            minBack = back;
            final = tmp;
        }else if(need==minNeed&&back<minBack){
            minBack=back;
            final = tmp;
        }
        tmp.pop_back();
        return;
    }
    for(int i=0;i<pre[index].size();i++)
        dfs(pre[index][i]);
    tmp.pop_back();
}

int main(){
    fill(dis,dis+505,INF);
    fill(e[0],e[0]+505*505,INF);
    scanf("%d%d%d%d",&c,&n,&p,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&weight[i]);
        weight[i] = weight[i]-c/2;
    }
    for(int i=0;i<m;i++){
        int a,b,l;
        scanf("%d%d%d",&a,&b,&l);
        e[a][b] = e[b][a] = l;
    }    

    dis[0] = 0;
    for(int i=0;i<=n;i++){
        int u=-1,min=INF;
        for(int j=0;j<=n;j++){
            if(visit[j]==false&&dis[j]<min){
                u = j;
                min = dis[j];
            }
        }
        if(u==-1)   break;
        visit[u] = true;
        for(int v=0;v<=n;v++){
            if(visit[v]==false&&e[u][v]!=INF){
                if(dis[u]+e[u][v]<dis[v]){
                    dis[v] = dis[u]+e[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }else if(dis[u]+e[u][v]==dis[v]){
                    pre[v].push_back(u);
                }
            }
        }
    }
    dfs(p);
    printf("%d 0",minNeed);
    for(int i=final.size()-2;i>=0;i--)
        printf("->%d",final[i]);
    printf(" %d",minBack);
    return 0;
}

dfs中正着再遍历一遍模拟调整 考试的时候不要不敢写!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值