文化之旅(dijstra)

时间:2021-06-06 06:38:12

2012_p4 文化之旅 (culture.cpp/c/pas)

时间限制: 1 Sec  内存限制: 128 MB
提交: 43  解决: 16
[提交][状态][讨论版][命题人:外部导入]

题目描述

4.文化之旅

(culture.cpp/c/pas)

【问题描述】

有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一

种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家)。不

同的国家可能有相同的文化。不同文化的国家对其他文化的看法不同,有些文化会排斥外来

文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)。

现给定各个国家间的地理关系,各个国家的文化,每种文化对其他文化的看法,以及这

位使者游历的起点和终点(在起点和终点也会学习当地的文化),国家间的道路距离,试求

从起点到终点最少需走多少路。

【输入】

输入文件 culture.in。

第一行为五个整数 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,两个国家之间可能有多条道路)。

【输出】

输出文件名为 culture.out。

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

果无解则输出-1)。

【输入输出样例 1】

culture.in

2 2 1 1 2

1 2

0 1

1 0

1 2 10

culture.out

-1

【输入输出样例说明】

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

【输入输出样例 2】

culture.in

2 2 1 1 2

1 2

0 1

0 0

1 2 10

culture.out

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≤N2,1≤ki≤K,1≤u, v≤N,1≤d≤1000,

S≠T,1 ≤S, T≤N。

输入

 

输出

 

提示

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int n,k,m,s,t;
int we[];
int g[][];
int e[][];
bool v[];
int d[];
void dijstra()
{
int i,j;
memset(v,,sizeof(v));
v[s]=;
for(i=;i<=n;i++) d[i]=e[s][i];
while()
{
int k=-;
int mm=inf;
for(i=;i<=n;i++)
{
if(!v[i]&&d[i]<mm)
{
k=i;
mm=d[i];
}
}
if(k==-) break;
v[k]=;
for(i=;i<=n;i++)
{
if(we[k]!=we[i]&&g[we[k]][we[i]]==&&d[i]>d[k]+e[k][i])
{
d[i]=d[k]+e[k][i];
}
}
}
} int main()
{
cin>>n>>k>>m>>s>>t;
int i,j;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
{
if(i==j) e[i][j]=;
else e[i][j]=inf;
}
for(i=;i<=n;i++)
cin>>we[i];
for(i=;i<=k;i++)
{
for(j=;j<=k;j++)
cin>>g[i][j];
}
for(i=;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(e[x][y]>z)
{
e[x][y]=z;
e[y][x]=z;
}
}
dijstra();
if(d[t]==inf) cout<<"-1";
else cout<<d[t];
return ;
}

思路:题目很明显就是个最短路问题,关键点是到达一个国家后,要判断该国家的文化是否排斥使者已掌握的文化,
这个可以用bitset去进行记录,比较省空间,判断时的速度也更快

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional> using namespace std; #define LL long long
const int INF = 0x3f3f3f3f; struct node
{
int id, dis;
bitset<>x;//1表示学会的文化,0表示不会的文化
bool operator<(const node &a)const
{
return dis > a.dis;
}
}pre, nt1; int n, m, k, ss, tt;
int s[], nt[], e[], val[], dis[];
int a[];//每个国家的文化
bitset<>x[];//某一种文化对其他文化是否排斥,1表示排斥,0表示不排斥 void Dijkstra()
{
memset(dis, INF, sizeof dis);
dis[ss] = ;
pre.dis = , pre.id = ss, pre.x.reset();
pre.x[a[ss]] = ;
priority_queue<node>q;
q.push(pre);
while (!q.empty())
{
pre = q.top();
q.pop();
if (pre.id == tt) break;
for (int i = s[pre.id]; ~i; i = nt[i])
{
int ee = e[i];
if ((pre.x & x[a[ee]]) != || pre.x[a[ee]] != ) continue;
//该国家的文化对使者已掌握的文化排斥或者该文化使者已掌握则跳过
if (dis[ee] > dis[pre.id] + val[i])
{
dis[ee] = dis[pre.id] + val[i];
nt1.id = ee, nt1.dis = dis[ee];
nt1.x = pre.x;
nt1.x[a[ee]] = ;
q.push(nt1);
}
}
}
if (dis[tt] == INF) dis[tt] = -;
printf("%d\n", dis[tt]);
} int main()
{
while (~scanf("%d %d %d %d %d", &n, &k, &m, &ss, &tt))
{
int cnt = ;
memset(s, -, sizeof s);
for (int i = ; i <= n; i++) scanf("%d", &a[i]), x[i].reset();
for (int i = ; i <= k; i++)
{
int tmp;
for (int j = ; j <= k; j++)
{
scanf("%d", &tmp);
x[i][j] = tmp;//每个文化对其他文化是否排斥
}
}
for (int i = ; i < m; i++)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
nt[cnt] = s[u], s[u] = cnt, e[cnt] = v, val[cnt++] = w;
nt[cnt] = s[v], s[v] = cnt, e[cnt] = u, val[cnt++] = w;
}
Dijkstra();
}
return ;
}