BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路

BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路

Description

虎是中国传统文化中一个独特的意象。我们既会把老虎的形象用到喜庆的节日装饰画上,也可能把它视作一种邪恶的可怕的动物,例如“武松打虎”或者“三人成虎”。“不入虎穴焉得虎子”是一个对虎的威猛的形象的极好体现,而小强确偏偏进入了虎穴,但问题是怎么出来。
  有一个复杂的虎穴包括了N个节点(编号为0至N-1)和M条无向的通道,其中通道i(0<=i<M)连接两个节点R[i][0]和R[i][1],长为L[i]。有K个出口节点,分别为P[0],

P[1]至P[K-1]。小强从0号节点出发,他想尽快到达一个出口节点。而洞穴中有一只会瞬间移动的老虎。小强每次到达一个节点,老虎就会瞬间移动到与这个节点相邻的某个通道里使得小强无法使用这个通道。不过,小强一旦选择了另一个没有被*的通道,老虎就不会在小强到达这个通道的目的地前改变位置。
  老虎非常聪明,它总能让小强离开洞穴所要消耗的时间最长。而小强也非常聪明,他能够计算出最快的逃生方案。
  为了让题目更加严谨,我们规定小强的逃生方案是如下的形式:对于每个节点X,给它的所有相邻的边<X,Y>指定一个权值f(X,Y),注意,f(X,Y)不等于f(Y,X);在一个节点,小强选择未被*的权值最大的通道逃生,直到到达出口。所有的f(X,Y)两两不同。
  你要计算小强的最快逃离时间T并输出。

Input

第一行三个整数 N M K
接下来M行 每行三个整数 表示一条无向边的两端和长度(无重边)
接下来K个整数 表示出口洞穴
输入直接保留这个就行

Output

Sample Input

13 12 9
0 1 1
0 2 4
0 3 11
1 4 11
1 5 7
1 6 15
2 7 3
2 8 13
2 9 23
3 10 3
3 11 1
3 12 2
4 5 6 7 8 9 10 11 12

Sample Output

13

从后往前思考,可以发现老虎每次封的点x一定是这条边的距离加上x到n的距离中最小的一个点。
因此每次转移时用次小值更新下一次的最小值,同时维护出这个点的次小值,再用这个次小值去更新前面的值。
用dij转移即可。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
#define N 100050
#define M 1000050
#define mr(x,y) make_pair(x,y)
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd() {
register int x=0;
register char s=nc();
while(s<'0'||s>'9')s=nc();
while(s>='0'&&s<='9')x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
int head[N],to[M<<1],nxt[M<<1],val[M<<1],cnt,n,m;
int f[N],k,g[N],vis[N];
priority_queue<pair<int,int> >q;
inline void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dij() {
int i;
while(!q.empty()) {
int x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=1;
for(i=head[x];i;i=nxt[i]) {
if(f[to[i]]>=g[x]+val[i]) {
g[to[i]]=f[to[i]];
f[to[i]]=g[x]+val[i];
q.push(make_pair(-g[to[i]],to[i]));
}else if(g[to[i]]>g[x]+val[i]) {
g[to[i]]=g[x]+val[i];
q.push(make_pair(-g[to[i]],to[i]));
}
}
}
}
int main() {
// freopen("tiger.in","r",stdin); freopen("tiger.out","w",stdout);
n=rd(); m=rd(); k=rd();
int i,x,y,z;
for(i=1;i<=m;i++) {
x=rd(); y=rd(); z=rd();
x++,y++;
add(x,y,z),add(y,x,z);
}
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
for(i=1;i<=k;i++) {
x=rd();
f[x+1]=g[x+1]=0;
q.push(make_pair(0,x+1));
}
dij();
printf("%d\n",g[1]); return 0;
}
上一篇:饮冰三年-人工智能-linux-04 vim编辑器


下一篇:bzoj 5120: [2017国家集训队测试]无限之环【最小费用最大流】