zoukankan      html  css  js  c++  java
  • PAT1018

    题目链接:http://pat.zju.edu.cn/contests/pat-a-practise/1018

    此题算比较难的,第一求最短路径,最短路径有多条时,要选出送出自行车最少的,当送出自行车最少的不止一个时,要选送回自行车最少的。

    我的思想:首先看到题,第一反应就是Dijkstra最短路径求,这么做需要在做Dij的同时,保存每个节点的相关信息,这样一次遍历足以。为了保存相应结点信息,设计了如下的数据结构。 map<int, vector<pair<Node, vector<int>>>> info; 描述如下图:

    map键值对key对应节点值,value为vector<pair<Node, vector<int>>>类型,用来存多条最短路径,Node 结点用来存collect和sent,vector<int>用来存取其中一条最短路径走过的所有节点(不包括自身)。

      

      剩下的工作就是在Dij时更新数据,在此说明下,有一点要注意的:若每个站点的perfect station = 5, 有如下最短路径序列, 2 3 6 5 1 8,第一次提交有2个case没过是因为如下思想,首先定义collect=0,走到2时,2-5=-3,代表需要从原点取3辆自行车,collect += -3, 然后, 3-5=-2,collect+=-2,以此类推,最后得collect=-5,表格如下,

    2 3 6 5 1 8
    -3 -5 -4 -4 -8 -5

    误以为需要从原点取5个自行车就够了,其实是错的。是因为车子是从前往后送的,不能用后面的补前面的!!正确的思路是这样的,2的时候需要3个,3的时候需要5个,以此类推,在1的时候需要8个,这时候需要量达到最大,所以需要从原点取8个自行车,所以用sent值来存储collect变化序列中最小的,当sent的值为负时,就代表需要从原点取自行车。

    接下来的问题就是求送回多少量,送回辆数 = -sent-(-collect)=collect-sent=-5-(-8)=3, 送回3辆,其实就是collect代表如果能拿后面的自行车来补前面的还需多少辆,而sent代表从前往后送至少送多少辆就足以。所以两者相减代表送回的车数。还有一种简单的情况如下:

    5 6 5 7 8 9
    0 1 0 3 6 11

      这种情况就是collect不会出现负值,就是代表不需要从原点取车,这种情况比较简单,而送回的车数就等于collect最后的值。

      主要思想如上,然后就是当找到一点较短路径时,将节点信息复制(i = kk),并做相应的collect ,sent值更新,以及将前驱结点加入vector<int>中, 若找到相同距离的路径,将此结点信息加入到目标节点中(kk的信息加入到i的信息中),再做类似更新。 

      最后直接找到S结点的信息,对所有最短路径排序选出最优,输出即可。

      1 #include<iostream>
      2 #include<map>
      3 #include<utility>
      4 #include<vector>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 #define INF 9999999
      9 
     10 struct Node
     11 {
     12     int sent;
     13     int collect;
     14 };
     15 
     16 /*排序谓词函数,用于选出最优路径,即是送出自行车最少,送回自行车最少*/
     17 bool comp(pair<Node, vector<int>> p1, pair<Node, vector<int>> p2)
     18 {
     19     if(p1.first.sent > p2.first.sent)
     20         return true;
     21     else if(p1.first.sent == p2.first.sent && p1.first.collect < p2.first.collect)
     22         return true;
     23     else
     24         return false;
     25 }
     26 
     27 void Dijkstra_version(vector<vector<int>> &gra, vector<int> &bike, int C, int S)
     28 {
     29     int start = 0;
     30     vector<int> used(gra.size(), 0);
     31     map<int, vector<pair<Node, vector<int>>>> info;
     32     /*保存每个结点的信息,信息表明到此结点有几条最短路径,
     33     分别是什么,以及需要从原点取及其放回多少量自行车*/
     34     vector<int> ri;
     35     Node n={INF, 0};
     36     pair<Node, vector<int>> zero(n,ri);
     37     info[0].push_back(zero);
     38     /*更新原点信息*/
     39     vector<int> dist(gra.size(), INF);
     40     dist[0] = 0;
     41     
     42     while(start != S)
     43     {
     44         int min = INF; int kk = -1;
     45         for(int i=0; i<dist.size(); ++i)
     46             if(used[i] == 0 && dist[i] < min)
     47             {
     48                 min = dist[i];
     49                 kk = i;
     50             }
     51         used[kk] = 1;
     52         for(int i=0; i<dist.size(); ++i)
     53             if(used[i] == 0)
     54                 if(gra[kk][i] + dist[kk] < dist[i])
     55                 {
     56                     dist[i] = gra[kk][i] + dist[kk];
     57                     /*当有较短路径出现时,替换原来结点的信息*/
     58                     info[i] = info[kk];
     59                     for(int j=0; j < info[i].size(); ++j)
     60                     {
     61                         /*替换后,对结点的信息更新,collect记录信息,此信息现在虽无具体意义,
     62                         但是后面要用它计算送回多少量自行车,sent用来记录从原来送出多少自行车*/
     63                         info[i][j].first.collect += (bike[i] - C/2);
     64                         if(info[i][j].first.collect < info[i][j].first.sent)
     65                             info[i][j].first.sent = info[i][j].first.collect;
     66                         info[i][j].second.push_back(kk);
     67                     }
     68                 }
     69                 else if(gra[kk][i] + dist[kk] == dist[i] && dist[i] != INF)
     70                 {
     71                     /*要把KK结点的信息更新并加入i节点中*/
     72                     for(int j=0; j < info[kk].size(); ++j)
     73                     {
     74                         info[i].push_back(info[kk][j]);
     75                         info[i][info[i].size()-1].first.collect += (bike[i] - C/2);
     76                         if(info[i][info[i].size()-1].first.collect < info[i][info[i].size()-1].first.sent)
     77                             info[i][info[i].size()-1].first.sent = info[i][info[i].size()-1].first.collect;
     78                         info[i][info[i].size()-1].second.push_back(kk);
     79                     }
     80                 }
     81         start = kk;
     82     }
     83     for(int i=0; i<info[S].size(); ++i)
     84     {
     85         /*若sent>=0,则代表不需要送出自行车,负数代表要送出自行车*/
     86         if(info[S][i].first.sent >= 0)
     87             info[S][i].first.sent = 0;
     88         else
     89         {
     90             /*更新collect,使collect最终表示有多少辆车要送回去*/
     91             info[S][i].first.collect -= info[S][i].first.sent;
     92         }
     93     }
     94     sort(info[S].begin(), info[S].end(), comp);
     95     /*排序得最优*/
     96     pair<Node, vector<int>> v=*(info[S].begin());
     97     cout<<0-v.first.sent<<" ";
     98     for(int i=0; i<v.second.size(); ++i)
     99         cout<<v.second[i]<<"->";
    100     cout<<S<<" "<<v.first.collect<<endl;
    101 }
    102 
    103 int main()
    104 {
    105     int C, N, S, M;
    106     while(cin>>C>>N>>S>>M)
    107     {
    108         vector<int> colum(N+1, INF);
    109         vector<vector<int>> gra(N+1, colum);
    110         vector<int> bikes(N+1,-1);
    111         for(int i=1; i<=N; ++i)
    112             cin>>bikes[i];
    113         for(int i=0; i<M; ++i)
    114         {
    115             int a,b,c; cin>>a>>b>>c;
    116             gra[a][b]=gra[b][a]=c;
    117         }
    118         Dijkstra_version(gra, bikes, C, S);
    119     }
    120     return 0;
    121 }
  • 相关阅读:
    Linux查看进程和已知端口是否启动
    plsql安装
    windows中用批处理文件删除n天前的文件
    阿里云服务器25邮件端口问题
    通过rpm安装crontab
    [RHEL7.1]关闭防火墙及SElinux
    有了 itchat, python 调用微信个人号从未如此简单(新增 py3 支持)
    Linux中tty、pty、pts的概念区别
    不用写代码就能实现深度学习?手把手教你用英伟达 DIGITS 解决图像分类问题
    Hadoop 2.7.3 安装配置及测试
  • 原文地址:https://www.cnblogs.com/bochen-sam/p/3355871.html
Copyright © 2011-2022 走看看