题目背景
NOIP2018 原创模拟题 T2
NOIP DAY1 T2 or DAY2 T2 难度
题目背景改编自小说《哈利波特与密室》。
说明:#4,bug经修复,感谢:@唐子川
题目描述
密室被打开了。
哈利与罗恩进入了密室,他们发现密室由n个小室组成,所有小室编号分别为:1,2,…,n。所有小室之间有m条通道,对任意两个不同小室最多只有一条通道连接,而每通过一条通道都需要Ci 的时间。
开始时哈利与罗恩都在编号为1的小室里,他们的目标是拯救金妮和寻找日记,但是他们发现金妮和日记可能在两个不同的小室里,为了尽快发现真相,他们决定以最少的时间到达两个目标小室。但是某些小室只有会与蛇对话的人才能进入,也就是只有哈利一个人可以进入。
现在,哈利告诉你密室的结构,请你计算他们到达两个目标小室的最短时间。
输入输出格式
输入格式:
第一行 n , m , k n,m,k n,m,k 表示有 n n n个小室 m m m条通道, k k k间小室只有哈利可以进入。
第二行 k k k 个数,表示只有哈利可以进入的小室的编号。(若 k = 0 k=0 k=0,不包含该行)
接下来 m m m行,每行 3 3 3个数: a , b , c a,b,c a,b,c 表示 a a a小室与 b b b小室之间有一条需要花费 c c c时间的通道。
最后一行,两个数 x , y x,y x,y 表示哈利与罗恩需要去的小室的编号
输出格式:
一行,输出一个数,表示到达两个密室的最短时间。
输入输出样例
输入样例#1:
6 8 1
5
1 2 3
2 3 2
1 3 4
3 4 1
4 6 5
5 6 2
1 6 6
1 5 3
4 6
输出样例#1:
5
输入样例#2:
10 13 3
3 4 10
1 2 1
2 3 2
3 4 3
4 5 4
5 6 5
6 7 10
7 8 5
8 9 10
9 10 3
10 1 2
1 9 6
3 8 10
4 6 3
6 8
输出样例#2:
16
说明
样例解释:
样例一:
哈利: 1 → 5 → 6 1\to5\to6 1→5→6 花费时间为 5 5 5
罗恩: 1 → 3 → 4 1\to3\to4 1→3→4 花费时间为 5 5 5
所以最短时间为 5 5 5
样例二:
图1
如图,橙色表示目标小室,绿色只有哈利可以通过
哈利: 1 → 2 → 3 → 4 → 6 1\to2\to3\to4\to6 1→2→3→4→6 花费时间为 9 9 9
罗恩: 1 → 9 → 8 1\to9\to8 1→9→8 花费时间为 16 16 16
所以最短时间为 16 16 16
数据范围:
10 % 10\% 10% 数据满足: n ≤ 5 n\le5 n≤5
30 % 30\% 30% 数据满足: n ≤ 20 n\le20 n≤20
50 % 50\% 50% 数据满足: n ≤ 1000 n\le1000 n≤1000
70 % 70\% 70% 数据满足: n ≤ 10000 n\le10000 n≤10000
100 % 100\% 100%数据满足: n ≤ 50000 a , b , k ≤ n c ≤ 1000 m ≤ 100000 n\le50000 \quad a,b,k\le n \quad c\le1000 \quad m\le100000 n≤50000a,b,k≤nc≤1000m≤100000,保证罗恩可以在密室 1 1 1
特殊约定:
30 % 30\% 30%数据满足: k = 0 k=0 k=0
建立一张完整的图和一张残图,分别跑两遍dijkstra,求出哈利到
x
,
y
x,y
x,y的最短路
d
i
s
[
1
]
[
x
]
,
d
i
s
[
1
]
[
y
]
dis[1][x],dis[1][y]
dis[1][x],dis[1][y]以及罗恩到
x
,
y
x,y
x,y的最短路
d
i
s
[
2
]
[
x
]
,
d
i
s
[
2
]
[
y
]
dis[2][x],dis[2][y]
dis[2][x],dis[2][y]。然后在全图上以
x
x
x为起点跑一遍dijkstra,求出到y的最短路d[y]。
所求即为:
min
(
max
(
d
i
s
[
1
]
[
x
]
,
d
i
s
[
2
]
[
y
]
)
,
max
(
d
i
s
[
2
]
[
x
]
,
d
i
s
[
1
]
[
y
]
)
,
m
i
n
(
d
i
s
[
1
]
[
x
]
,
d
i
s
[
1
]
[
y
]
)
+
d
[
y
]
)
\min\Big(\max(dis[1][x],dis[2][y]),\max(dis[2][x],dis[1][y]),min(dis[1][x],dis[1][y])+d[y]\Big)
min(max(dis[1][x],dis[2][y]),max(dis[2][x],dis[1][y]),min(dis[1][x],dis[1][y])+d[y])
时间复杂度
O
(
算
不
来
)
O(算不来)
O(算不来)
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=5e4+10;
const int M=1e5+10;
const int INF=2e9;
int n,m,k,hd[3][N],tot[3],dis[3][N],x,y,d[N],vis[N];
bool ban[N];
struct Edge{
int v,w,nx;
}e[3][M<<1];
struct Node{
int to,w;
Node(){}
Node(int _to,int _w):to(_to),w(_w){}
bool operator <(const Node&rhs)const{
return w>rhs.w;}
};
void add(int id,int u,int v,int w)
{
e[id][tot[id]].v=v;
e[id][tot[id]].w=w;
e[id][tot[id]].nx=hd[id][u];
hd[id][u]=tot[id]++;
}
void dijkstra(int id)
{
fill(dis[id],dis[id]+N,INF);
memset(vis,0,sizeof(vis));
priority_queue<Node>q;while(q.size())q.pop();
q.push(Node(1,0));dis[id][1]=0;
while(q.size())
{
Node tmp=q.top();q.pop();
int u=tmp.to;
vis[u]=1;
for(int i=hd[id][u];~i;i=e[id][i].nx)
{
int v=e[id][i].v,w=e[id][i].w;
if(dis[id][v]>dis[id][u]+w)
{
dis[id][v]=dis[id][u]+w;
if(!vis[v])q.push(Node(v,dis[id][v]));
}
}
}
}
void Dijkstra()
{
fill(d,d+N,INF);
memset(vis,0,sizeof(vis));
priority_queue<Node>q;while(q.size())q.pop();
q.push(Node(x,0)),d[x]=0;
while(q.size())
{
Node tmp=q.top();q.pop();
int u=tmp.to;vis[u]=1;
for(int i=hd[1][u];~i;i=e[1][i].nx)
{
int v=e[1][i].v,w=e[1][i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
if(!vis[v])q.push(Node(v,d[v]));
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
memset(hd,-1,sizeof(hd));
scanf("%d%d%d",&n,&m,&k);
int u,v,w;
for(int i=1;i<=k;i++)scanf("%d",&u),ban[u]=true;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(1,u,v,w);add(1,v,u,w);
if(ban[u]||ban[v])continue;
add(2,u,v,w);add(2,v,u,w);
}
scanf("%d%d",&x,&y);
dijkstra(1);dijkstra(2);
int ans=min(max(dis[1][x],dis[2][y]),max(dis[2][x],dis[1][y]));
Dijkstra();
ans=min(ans,min(dis[1][x],dis[1][y])+d[y]);
printf("%d\n",ans);
return 0;
}
总结
实际还是一个最短路问题,建不建两个图都无所谓(题解就没有建双份),然后就是一个分类讨论,很简单,对比NOIP2017DAY1T2……