2020/10/23 模拟赛 escape
Description
小恩听说有人想在邻国放置SD反导系统十分不满,为了做好应对导弹战的准备,小恩进行 了新的军队部署。 小恩的国家有 $n$个城市 $m$条无向道路,每条边长度都是正值。现在小恩想从$1$号城市向$n$ 号城市转移部分军队。由于这支部队已经多次执行了从$1$号城市到$n$号城市转移的任务,他们 己经走过了所有从$1$号到$n$号所有可能的最短路。为了迷惑敌国,小恩决定走剩下的路径中最 短的那一条简单路径,但又为了照顾到士兵的情绪,小恩要求这条路径如果经过了某些之前进行 从$1$到$n$的最短路转移时走过的道路,则这些道路必须按照原来的方向前进。现在问满足条件 的道路最短是多少。
Solution
图中要求一条有限制的次短路的长度
有一个二进制分组的非正解方法
给每一个点分配编号,设定集合$A_1,A_2, \cdots ,A_{18}$,集合$B_1,B_2, \cdots , B_{18}$,$A$集合表示在最短路上的编号第$i$位为0的点,$B$集合表示在最短路上的编号第$i$位为1的点
如此操作可以使任意一对点至少在一种情况下分属$A$、$B$两个集合
所以可以由$A$向$B$跑最短路,不经由最短路上的边,再由$B$向$A$重复一边
只加入在最短路上的点是因为题目要求简单路径,若不如此可能会出现路径重叠
实际上跑上几次正确率就已经非常高了,所以可以卡时
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<ctime> using namespace std; long long n,m,tot=1,head[100005],dist[100005],sdis[100005],tdis[100005],que[100005],top,A[100005],a,B[100005],b,ans=1<<30,len; bool vst[100005],ban[2000005],tag[100005]; struct Edge { long long to,nxt,w,sta; }edge[2000005]; queue<long long>q; inline long long read() { long long f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } void SPFA() { while(q.size()) { long long u=q.front(); q.pop(); vst[u]=false; for(long long i=head[u];i;i=edge[i].nxt) { if(ban[i]) { continue; } long long v=edge[i].to; if(dist[v]>dist[u]+edge[i].w) { dist[v]=dist[u]+edge[i].w; if(!vst[v]) { q.push(v); vst[v]=true; } } } } } int main() { n=read(); m=read(); for(long long i=1;i<=m;i++) { long long x=read(),y=read(),u=read(); edge[++tot]=(Edge){y,head[x],u,x}; head[x]=tot; edge[++tot]=(Edge){x,head[y],u,y}; head[y]=tot; } memset(dist,127,sizeof(dist)); q.push(1); vst[1]=true; dist[1]=0; SPFA(); for(long long i=1;i<=n;i++) { sdis[i]=dist[i]; } len=dist[n]; memset(dist,127,sizeof(dist)); q.push(n); vst[n]=true; dist[n]=0; SPFA(); for(long long i=1;i<=n;i++) { tdis[i]=dist[i]; } for(long long i=2;i<=tot;i++) { if(sdis[edge[i].sta]+edge[i].w+tdis[edge[i].to]==len) { if(!tag[edge[i].sta]) { que[++top]=edge[i].sta; } if(!tag[edge[i].to]) { que[++top]=edge[i].to; } tag[edge[i].sta]=tag[edge[i].to]=ban[i]=ban[i^1]=true; } } for(long long i=0;i<=17;i++) { a=b=0; for(long long j=1;j<=top;j++) { if(que[j]&(1<<i)) { A[++a]=que[j]; } else { B[++b]=que[j]; } } memset(dist,127,sizeof(dist)); for(long long j=1;j<=a;j++) { dist[A[j]]=sdis[A[j]]; q.push(A[j]); vst[A[j]]=true; } SPFA(); for(long long j=1;j<=b;j++) { ans=min(ans,dist[B[j]]+tdis[B[j]]); } swap(a,b); swap(A,B); memset(dist,127,sizeof(dist)); for(long long j=1;j<=a;j++) { dist[A[j]]=sdis[A[j]]; q.push(A[j]); vst[A[j]]=true; } SPFA(); for(long long j=1;j<=b;j++) { ans=min(ans,dist[B[j]]+tdis[B[j]]); } if(clock()>1.5*CLOCKS_PER_SEC) { break; } } printf("%lld\n",ans); return 0; }