蓝桥杯 ALGO-178 The Traveling Judges Problem(试题解析)

试题 算法训练 The Traveling Judges Problem

提交此题   评测记录  

资源限制

时间限制:1.0s   内存限制:256.0MB

问题描述

  一组人要担任在一个特定城市举办的比赛的评委,他们需要找到最便宜的租车方式使得每个人都到达目标城市。他们观察发现,如果几个人在旅途的某一段坐同一辆租的车,就可以减少总费用。你的任务就是找出这些人应该采取的路线使得租车的总费用最小。
  我们假定:
  1. 租一辆车的费用与它行驶的距离成正比,没有燃油、保险、乘客人数多于一个等产生的额外费用。
  2. 所有车的费用与行驶距离的比例相同。
  3. 一辆车可以容纳任意数量的乘客。
  4. 任意一对城市之间最多只有一条道路直接相连,每条道路都是双向的且长度大于0。
  5. 每个人的起始城市到目标城市都至少有一种路线。
  6. 若多个人的路线中经过同一城市,则这些人从该城市到目标城市必乘同一辆车。
  7. 一个人可以乘一辆车到某个城市,再乘另一辆车离开该城市。

输入格式

  第一行包含三个整数nc, dc和nr,表示地图上的城市个数,目标城市的编号和地图上的道路条数。
  接下来nr行每行包含三个整数c1, c2和dist,表示一条长度为dist的双向道路(c1, c2)。
  接下来一行包含一个整数nj,表示人数。
  接下来一行包含nj个整数,表示每个人的起始城市。

输出格式

  第一行包含“distance = ”和一个整数,表示所租的车行驶的最小总距离。
  接下来nj行每行包含一个人的访问路线,城市按访问顺序给出并用“-”连接。
  存在多种方案时,选择需要访问到的城市集合元素最少的一种;仍然存在多种方案时,选择集合元素升序排列后字典序最小的一种。

样例输入

5 3 5
1 2 1
2 3 2
3 4 3
4 5 1
2 4 2
2
5 1

样例输出

distance = 6
5-4-2-3
1-2-3

样例输入

4 4 3
1 3 1
2 3 2
3 4 2
2
1 2

样例输出

distance = 5
1-3-4
2-3-4

样例输入

3 3 3
1 2 2
1 3 3
2 3 1
2
2 1

样例输出

distance = 3
2-3
1-2-3

数据规模和约定

  对于30%的数据,1 <= nc <= 8。
  对于100%的数据,1 <= nc <= 20,1 <= nj <= 10,1 <= dist <= 100。

 

解题思路:先用Prim 算法(当所有起始城市都被访问过时 退出while循环),得出最小生成树。然后,遍历每个起始城市,不断向前回溯,访问其父节点,得到每段路径,若该路径未被访问(数组Cvis[i][j]  记录 城市i 与城市j 之间的道路 是否被访问),则加到res中;否则,跳过。 遍历结束后的res 即为 最终的distance。找每个起始城市到达dc的路径也是 向前回溯。代码只跑了40分,可能是  “存在多种方案时,选择需要访问到的城市集合元素最少的一种;仍然存在多种方案时,选择集合元素升序排列后字典序最小的一种。” 没处理好的问题。。。未完待续。。。

 

代码如下:

#include <iostream>
#include <queue>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;

#define MAXNC 22
struct Way{
    int c1,c2;
    int dist;
    Way(){    }
    Way(int cc1,int cc2,int dd):c1(cc1),c2(cc2),dist(dd){    }
    bool operator <(const Way &W) const {
        return dist>W.dist;
    }
    
};

int father[MAXNC];
int vis[MAXNC];
int     isSC[12];
int Cvis[MAXNC][MAXNC];// Gvis[i][j] 记录 城市i 与城市j 之间的道路 是否被访问, 

vector<int>    SC;

priority_queue<Way>     PQ;
vector< Way>    G[MAXNC];

int nc, dc,nr;    //表示地图上的城市个数,目标城市的编号和地图上的道路条数。
int nj;

bool isAllReached(){
    bool isAll=true;
    for(int i=0;i<SC.size();i++){
        int sc=SC[i];
        if(vis[sc]==0){
            isAll=false;
            break;
        }
    }
    return isAll;
}

void ReadInput(){
    cin>>nc>>dc>>nr;
    
    int c1,c2,dist;
    for(int i=1;i<=nr;i++){
        cin>>c1>>c2>>dist;
        G[c1].push_back(Way(c1,c2,dist));
        G[c2].push_back(Way(c2,c1,dist));    
    }
    
    memset(isSC,0,sizeof(isSC));
    memset(vis,0,sizeof(vis));
    cin>>nj;
    for(int i=0;i<nj;i++){
        int sc;
        cin>>sc;
        isSC[sc]=1;
        SC.push_back(sc);
    }
    
    for(int i=1;i<=nc;i++)
        father[i]=i;
    
}

void  Prim(int S){
//    long long res=0;
    vis[S]=1;
    for(int i=0;i<G[S].size();i++){
        int to=G[S][i].c2;
        father[to]=S;
        PQ.push(G[S][i]);
        
    }
    
    while(!PQ.empty()){
        Way W=PQ.top();
        PQ.pop();
        if(vis[W.c2])
            continue;
        
        vis[W.c2]=1;
    //    res+=W.dist;
        father[W.c2]=W.c1;
        for(int i=0;i<G[W.c2].size();i++)
            PQ.push(G[W.c2][i]);
        if( isAllReached() )
            break;    
    }
    
}

int findDist(int c1,int c2){
    
    for(int i=0;i<G[c1].size();i++){
        int to=G[c1][i].c2;
        if(to==c2){
            return G[c1][i].dist;
        }
    }
}

long long getTotalDist(){
    memset(Cvis,0,sizeof(Cvis));
    
    long long res=0; 
    for(int i=0;i<SC.size();i++){            
        int pos=SC[i];        
        while(1){
            if( Cvis[pos][father[pos]]==0 ){
                res+=findDist(pos,father[pos]);
                Cvis[pos][father[pos]]=Cvis[ father[pos] ][ pos ]=1;
            }                
            pos=father[pos];
            if(father[pos]==pos)
                break;                
        }    
    }
    return res;
}

int main(int argc, char** argv) {
    ReadInput();
    cout<<"distance = ";
    if(nj==1){
        cout<<"0"<<endl;
        cout<<SC[0]<<endl;
    }
        
    else{
        Prim(dc);
        cout<<getTotalDist()<<endl;
        for(int i=0;i<SC.size();i++){
            
            int pos=SC[i];
            cout<<pos<<"-";
            while(1){
                pos=father[pos];
                cout<<pos;
                if(father[pos]==pos)
                    break;
                cout<<"-";
            }
            cout<<endl;
        }
    }
        
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值