蓝桥杯 ADV-195 VIP试题 文化之旅(试题解析)

试题 算法提高 文化之旅

提交此题   评测记录  

资源限制

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

问题描述

  有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家)。不同的国家可能有相同的文化。不同文化的国家对其他文化的看法不同,有些文化会排斥外来文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)。
  现给定各个国家间的地理关系,各个国家的文化,每种文化对其他文化的看法,以及这位使者游历的起点和终点(在起点和终点也会学习当地的文化),国家间的道路距离,试求从起点到终点最少需走多少路。

输入格式

  第一行为五个整数N,K,M,S,T,每两个整数之间用一个空格隔开,依次代表国家个数(国家编号为1到N),文化种数(文化编号为1到K),道路的条数,以及起点和终点的编号(保证S不等于T);
  第二行为N个整数,每两个整数之间用一个空格隔开,其中第i个数Ci,表示国家i的文化为Ci。
  接下来的K行,每行K个整数,每两个整数之间用一个空格隔开,记第i行的第j个数为aij,aij= 1表示文化i排斥外来文化j(i等于j时表示排斥相同文化的外来人),aij= 0表示不排斥(注意i排斥j并不保证j一定也排斥i)。
  接下来的M行,每行三个整数u,v,d,每两个整数之间用一个空格隔开,表示国家u与国家v有一条距离为d的可双向通行的道路(保证u不等于v,两个国家之间可能有多条道路)。

输出格式

  输出只有一行,一个整数,表示使者从起点国家到达终点国家最少需要走的距离数(如果无解则输出-1)。

样例输入

2 2 1 1 2
1 2
0 1
1 0
1 2 10

样例输出

-1

输入输出样例说明

  由于到国家2必须要经过国家1,而国家2的文明却排斥国家1的文明,所以不可能到达国家2。

样例输入

2 2 1 1 2
1 2
0 1
0 0
1 2 10

样例输出

10

输入输出样例说明

  路线为1 -> 2。

数据规模和约定

  对于20%的数据,有2≤N≤8,K≤5;
  对于30%的数据,有2≤N≤10,K≤5;
  对于50%的数据,有2≤N≤20,K≤8;
  对于70%的数据,有2≤N≤100,K≤10;
  对于100%的数据,有2≤N≤100,1≤K≤100,1≤M≤ N^2,1≤ki≤K,1≤u, v≤N,1≤d≤1000,S≠T,1 ≤S, T≤N。

解题思路:构图,有Dijkstra 算法找最短路  外加 可到达判定条件(“不同文化的国家对其他文化的看法不同,有些文化会排斥外来文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)”)。

 

AC代码如下:

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

#define INF 65535

struct Way{
    int from,to;
    int val;
    Way(int ff,int tt,int vv):from(ff),to(tt),val(vv){    }
    Way(){    }
    bool operator <(const Way &W) const{
        return val>W.val;
    }
};

int CTC[110];// 第i个国家的文化 为 CTC[i] 
int cvis[110];// 文化i 是否可以被访问:0,可以;1,不可以。 也就是,之前已访问的文化是否排斥 文化i ,其实没用到 
vector< vector<int> >    Anti(110);// 文化i 排斥的文化 在 向量Anti[i]中 
vector< vector<Way> >    G(110);//图 
int N,K,M,S,T;
int d[110];
vector<int>    Learned;//已经学习的文化 

void Read(){
    cin>>N>>K>>M>>S>>T;
    
    for(int i=1;i<=N;i++){
        cin>>CTC[i];    //第i个数Ci,表示国家i的文化为Ci。
    }
    
    for(int i=1;i<=K;i++){
        for(int j=1;j<=K;j++){
            int a;
            cin>>a;
            if(a==1)
                Anti[i].push_back(j);
        }
    }
    
    for(int i=1;i<=M;i++){
        int u,v,d;
        cin>>u>>v>>d;
        G[u].push_back(Way(u,v,d));
        G[v].push_back(Way(v,u,d));    
    }    
    
    //初始化d
    for(int i=1;i<=N;i++){
        d[i]=INF;
    } 
}        

bool isAnti(int SC){
    
    for(int i=0;i<Anti[SC].size();i++){
        int curA=Anti[SC][i];
        for(int j=0;j<Learned.size();j++){
            int lnd=Learned[j];
            if(curA==lnd){
                return true;
            }
        }
    }
    
    return false;
}

void Dijkstra(){
    //memset(cvis,0,sizeof(cvis));
    priority_queue<Way>    PQ;
    d[S]=0;
    Learned.push_back(CTC[S]);
    PQ.push(Way(S,S,d[S]));
    
    while(!PQ.empty()){
        int now=PQ.top().from;
        PQ.pop();
        
        for(int i=0;i<G[now].size();i++){
            int to=G[now][i].to;
            if(d[now]+G[now][i].val<d[to] && !isAnti(CTC[to]) ){
                d[to]=d[now]+G[now][i].val;
                Learned.push_back(CTC[to]);
                PQ.push(Way(to,to,d[to]));
            }
        }
        
    }
    if(d[T]==INF)
        cout<<"-1"<<endl;
    else 
        cout<<d[T]<<endl;    
        
}

int main(int argc, char** argv) {
    Read();
    Dijkstra();
    
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值