1. 程式人生 > 實用技巧 >2020/10/23 模擬賽 escape

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; }
escape