【BZOJ2622】[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并输出。
Solution:
不是太显然的非传统次短路题。
我们思考一下老虎在做什么:对于每个节点,我们dijkstra时不能走最短路所在的路(这里的最短路指的是如果u在S->T的最短路上,那么u不能走S->T最短路上的那条边,而不所有以u为端点的边中,w值最小的那条)
但是鉴于这题的t可能有很多,而且图还是无向,所以我们考虑跑T->S的次短路:
对于每个节点记录dis[0]和dis[1]。分别表示到此节点的最短路和次短路,那么dijkstra的更新就比较显然了:
对于 u->v 将dis[u][1]+w[i] 传给 dis[v][1] 如果dis[v][1]<dis[v][0],则交换
然后这题就愉快的做完了
#include<bits/stdc++.h> const int N=2e5+5; const int M=2e6+6; const int inf=1e9; using namespace std; int n,m,k,e_cnt; struct Node{ int id,val[2]; bool operator<(const Node &k)const{ return k.val[1]==val[1] ? (k.val[0]<val[0]) : (k.val[1]<val[1]); } }; int dis[N][2],head[N],vis[N]; struct Edge{ int to,nxt,w; }e[M<<1]; void add(int x,int y,int w) { e[++e_cnt]=(Edge){y,head[x],w};head[x]=e_cnt; } void init() { for(int i=0;i<N;i++) { dis[i][0]=dis[i][1]=inf; } } priority_queue<Node> Q; void dijkstra() { while(!Q.empty()) { int u=Q.top().id;Q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to,w=e[i].w; if(dis[v][1]>dis[u][1]+w) { dis[v][1]=dis[u][1]+w; if(dis[v][1]<dis[v][0])swap(dis[v][1],dis[v][0]); Node push; push.id=v,push.val[0]=dis[v][0],push.val[1]=dis[v][1]; Q.push(push); } } } } void work() { cin>>n>>m>>k; for(int i=1,x,y,w;i<=m;i++) { scanf("%d%d%d",&x,&y,&w); add(x,y,w);add(y,x,w); } init(); for(int i=1,v;i<=k;i++) { scanf("%d",&v); dis[v][0]=dis[v][1]=0; Node push; push.id=v,push.val[0]=dis[v][0],push.val[1]=dis[v][1]; Q.push(push); } dijkstra(); printf("%d",dis[0][1]); } #undef int int main() { freopen("croad.in","r",stdin); freopen("croad.out","w",stdout); work(); return 0; }