文化之旅

题目描述

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

 

输入

第一行为五个整数 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)。

 

样例输入

【输入样例 1】
2 2 1 1 2
1 2
0 1
1 0
1 2 10

【输入样例 2】
2 2 1 1 2
1 2
0 1
0 0
1 2 10

 

样例输出

【输出样例 1】
-1
【输出样例 2】
10

 

提示

【输入输出样例1说明】 
由于到国家 2 必须要经过国家 1,而国家 2 的文明却排斥国家 1 的文明,所以不可能到 达国家 2。 
【输入输出样例2说明】 
路线为 1 -> 2。 
【数据范围】 
有 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。 

这个题就是最短路径的问题,只不过加了一些约束条件,在用地杰斯特拉寻找最短路径的过程中,如果遇到某些国家的文化使者已经学习过,或者某些国家的文化排斥使者已经学过的文化,那么这些国家就直接pass,剩下的就是套地杰斯特拉板子

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
const int INF = 2e9+5;
const int mod = 1000007;
const int N = 105;
const int M = 10005;
bool vi[105];
struct Node {
	int to;
	int dis;
	bool operator <(const Node &x)const {
		return x.dis < dis;
	}
};
priority_queue<Node> p;
int n, k, m, s, t;

int dis[N];
int head[N];
int ci[N];
int a[105];
bool aij[N][N];
struct Edge {
	int to;
	int dis;
	int next;
}edge[M * 2];
int cnt = 0;
void add(int a, int b, int c) {
	edge[++cnt].to = b;
	edge[cnt].dis = c;
	edge[cnt].next = head[a];
	head[a] = cnt;
}

void dijkstra(int s) {
	dis[s] = 0;
	Node no;
	no.to = s;
	no.dis = 0;
	p.push(no);
	while (!p.empty()) {
		Node node = p.top();
		p.pop();
		
		int cur = node.to;
		vi[ci[cur]] = true;
		for (int i = head[cur]; i != -1; i = edge[i].next) {
			int to = edge[i].to;
			int d = edge[i].dis;
			bool flag = false;
			for (int i = 1; i <= n; i++) {
				if ((aij[ci[to]][i]&&vi[i])||vi[ci[to]]) {//约数条件,(aij[ci[to]][i]&&vi[i])代表要去的to国家的文化排斥使者已经学习过的文化vi【i】
					//vi[ci[to]]代表要去的国家的文化ci【to】使者已经访问过
					flag = true;
					break;
				}
			}
			if (flag)
				continue;//如果要访问的点(国家)不满足条件,continue
			if (dis[to] > dis[cur] + edge[i].dis) {
				dis[to] = dis[cur] + edge[i].dis;
				Node nod;
				nod.dis = dis[to];
				nod.to = to;
				p.push(nod);

			}


		}

	}


}
int main() {
	memset(vi, false, sizeof(vi));//vi【i】代表文化i使者已经学习过,首先初始化false
	memset(head, -1, sizeof(head));
	cin >> n >> k >> m >> s >> t;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &ci[i]);//ci【i】代表国家i的文化种类
	}
	int x;
	for (int i = 1; i <= n; i++) {
		dis[i] = INF;//将边初始化无穷
	}
	for (int i = 1; i <= k; i++) {
		for (int j = 1; j <= k; j++) {
			scanf("%d", &x);
			if (x) {
				aij[i][j] = true;//aij[i][j]代表i文化是否排斥j文化
			}
			else {
				aij[i][j] = false;
			}
		}
	}

	int u, v, d;
	for (int i = 1; i <= m; i++) {//邻接表存图
		scanf("%d%d%d", &u, &v, &d);
		add(u, v, d);
		add(v, u, d);
	}
	dijkstra(s);

	if (dis[t] == INF)
		printf("-1");
	else
		printf("%d", dis[t]);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值