PAT甲级 1018 Public Bike Management(30) (Dijkstra+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 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

题意理解

给你一个固定起点 0,也就是PBMC的位置,本题起点位置固定

然后输入C_max,也就是一个点能存放多少辆自行车,而完美的状态是这个点最大存放量的一半,数据保证最大量一定是一个偶数,然后n个点,一个终点,m条边。

然后n个读入读入每个点目前的自行车量。

然后m条边 起点 终点 距离

这题要输出路径

所以我们要将所有的路径都用Dijkstra算法保留下来 然后在用DFS回溯路径

那么什么是最优路径呢,我们通过优先级表示

1.最大优先级:最短路

无论其他什么情况 我们都要保证一定是最短路 用Dijkstra维护 而且我们在跑Dijkstra的时候顺便把每个结点的前驱结点都记录下来 当出现了距离更短的时候 我们把这个节点之前加入的前驱节点全部删除,因为已经不是最优了,然后加入我们距离更短的这个前驱节点 最后我们就得到了所有路径 之后再用DFS去回溯寻找最优路径

2.第二优先级:从起点带出去的车要最少

当保证了最短路以后,我们每个路径上每个节点都会放入和放出自行车,一开始每个节点就有一些自行车数量,如果这个点大于完美状态,那么我们就不用放入自行车,甚至还可以拿走一些补充路径上面其他的点的自行车数量,如果小于这个自行车,我们就要用我们手上从别的点回收来的自行车补充进这个点,使得这个点到达完美状态。如果等于完美状态,那么这个点不做处理。当最短路一样时,我们要保证最后我们从起点带出去的自行车数量最少。

3.第三优先级:带回起点的车要最少

当保证了最短路距离一样,带出去的车辆一样时,我们现在选择带回起点的车要最少,也就会是,带回来的数量最少,如果这个点大于完美状态的车辆数,那么我们就要带走那些多余的车辆,在保证前面两个优先级时,再来看我们能不能带回的最少

这就是题意所有的思路

那么怎么用DFS回溯呢?

在一开始读入自行车数量的时候就开始处理,这个点的数量-完美状态(最大数量的一半)

如果大于0那么就要带走自行车
如果小于0那么就要放入自行车

然后我们跑Dijkstra 顺便记录路径

我们之前已经用Dijkstra算法把每个路径上面的前驱记录好了

那么我们从终于回溯回去的时候记录一个临时路径,和这条临时路径上面分别要带回去多少自行车,分别要带过来多少自行车

在所有路径中找到一条最优的 如果这条路径比之前别的路径更优 那么我们赋给ans也即是结果路径

注意ans此时是回溯的一条路径,也就是终点跑到起点,那么我们翻转一下就是我们最后想要的路径了

代码 

#include<bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef unsigned long long ULL ;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;
#define fx first
#define fy second
const int INF=0x3f3f3f3f;
const LL  LINF=1e18;
const int N=1010;
const int M=2e2+10;
const int MOD=1e9+7;
int h[N],e[N<<1],ne[N<<1],w[N<<1],idx;
void add(int a,int b,int c){
    e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
int Cmax,n,en,m;//每个点最大自行车容量 n个点 en终点 m条边
int C_num[N];//当前点缺自行车个数
int dis[N];
bool st[N];
vector<int>pre[N];//这个结点的前驱结点
void dijkstra(){
     memset(dis,INF,sizeof dis);
     memset(st,0,sizeof st);
     priority_queue<PII,vector<PII>,greater<PII> >heap;
     dis[0]=0;
     heap.push({0,0});
     while(heap.size()){
         PII t=heap.top();
         heap.pop();
         int ve=t.fy;
         if(st[ve])continue;
         st[ve]=1;
         for(int i=h[ve];~i;i=ne[i]){
             int j=e[i],c=w[i];
             if(dis[j]>dis[ve]+c){
                 pre[j].clear();
                 pre[j].push_back(ve);
                 dis[j]=dis[ve]+c;
                 heap.push({dis[j],j});
             }
             else if(dis[j]==dis[ve]+c){
                 pre[j].push_back(ve);
                 dis[j]=dis[ve]+c;
                 heap.push({dis[j],j});
             }
         }
     }
}
vector<int>path,tempPath;//最终回溯的路径 临时路径
int ans_need=INF,ans_back=INF;//need是从起点带出去的 back是结束之后带回来的
void dfs(int u,int s){
     if(u==s){//到达起点了
         tempPath.push_back(u);
         int need=0,back=0;
         //从起点后面一个点开始
         for(int i=tempPath.size()-2;i>=0;i--){
             int j=tempPath[i];
             //这个点自行车数量符合要求 无需处理
             if(!C_num[j])continue;
             //需要带走那么多辆自行车
             else if(C_num[j]>0){
                 back+=C_num[j];
             }
             //需要放入那么多辆自行车
             else if(C_num[j]<0){
                  //如果我现在的手头剩余的数量够发
                  if(back>=abs(C_num[j])){
                      back-=abs(C_num[j]);
                  }
                  //如果不够就要申请那么多辆车
                  else{
                      need+=abs(C_num[j])-back;
                      back=0;
                  }
             }
         }
         //如果这条路径带出去的少 那么更新
         if(need<ans_need){
            path=tempPath;
            ans_need=need;
            ans_back=back;
         }
         //如果这条路径带出去的车一样 判断带回来的能不能更新
         else if(need==ans_need){
             if(back<ans_back){
                 path=tempPath;
                 ans_need=need;
                 ans_back=back;
             }
         }
         return;
     }
     
     tempPath.push_back(u);
     
     for(int i=0;i<pre[u].size();i++){
         int j=pre[u][i];
         dfs(j,s);
         tempPath.pop_back();
     }
       
}
void solve(){
         memset(h,-1,sizeof h);idx=0;
    
         scanf("%d%d%d%d",&Cmax,&n,&en,&m);
         
         for(int i=1;i<=n;i++){
             scanf("%d",&C_num[i]);
             C_num[i]=C_num[i]-Cmax/2;
             //如果大于0那么就要带走自行车
             //如果小于0那么就要放入自行车
         }
         
         for(int i=1;i<=m;i++){
             int a,b,c;
             scanf("%d%d%d",&a,&b,&c);
             add(a,b,c);
             add(b,a,c);
         }
         
          dijkstra();
          
          dfs(en,0);//终点回溯回去
         
        //  cout<<dis[en]<<endl;
        
          reverse(path.begin(),path.end());
          
          printf("%d ",ans_need);
          
          for(int i=0;i<path.size();i++){
              if(i)printf("->");
              printf("%d",path[i]);
          }
          
          printf(" %d",ans_back);
}
int main(){
    int T=1;
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    while(T--){
    	solve();
	}
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值