CF715B Complete The Graph
阿新 • • 發佈:2020-12-22
一、題目
二、解法
這道題可以考慮微調法,也就是首先把不定權值都設定成 \(1\),然後再慢慢調整
具體來說,我們把某一個不定權值增加 \(1\) ,你會發現最短路不會降低,而且最多增加 \(1\) 的。這樣如果我們微調了足夠的次數就一定能取到要的最短路。
現在我們考慮加速微調的過程,設 \(x_i\) 為第 \(i\) 個不定邊,那麼我們依次調整 \(x_1,x_2.....\) 可以二分微調的次數,那麼所有邊的權值都知道了。計算出最短路之後,我們用最短路長度去判斷下一次往哪邊分。不難發現如果存在答案的話是一定能被二分出來的。
時間複雜度 \(O(m\log n\log (ml))\)
還有一個跑兩遍最短路的做法,也就是第二次讓 \(s\) 到所有點的最短路都增加一開始最短路和目標長度的差值,這樣的複雜度 \(O(m\log n)\),雖然十分優秀但我感覺十分難想。最後給出微調法的程式碼:
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; const int M = 100005; #define int long long int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,L,cnt,s,t,tot,f[M],a[M],b[M],c[M],tag[M],dis[M]; struct edge { int v,c,next; }e[2*M]; struct node { int u,c; bool operator < (const node &b) const { return c>b.c; } }; int dij() { priority_queue<node> q; q.push(node{s,0}); memset(dis,0x3f,sizeof dis); dis[s]=0; while(!q.empty()) { node t=q.top();q.pop(); if(dis[t.u]<t.c) continue; for(int i=f[t.u];i;i=e[i].next) { int v=e[i].v,c=e[i].c; if(dis[v]>dis[t.u]+c) { dis[v]=dis[t.u]+c; q.push(node{v,dis[v]}); } } } return dis[t]; } int check(int x)//返回序列長度是x的最短路長度 { tot=0; memset(f,0,sizeof f); for(int i=1;i<=m;i++) { int ct=c[i]; if(tag[i]) ct+=x/cnt+(x%cnt>=tag[i]); e[++tot]=edge{a[i],ct,f[b[i]]},f[b[i]]=tot; e[++tot]=edge{b[i],ct,f[a[i]]},f[a[i]]=tot; } return dij(); } void print(int x) { puts("YES"); for(int i=1;i<=m;i++) { int ct=c[i]; if(tag[i]) ct+=x/cnt+(x%cnt>=tag[i]); printf("%lld %lld %lld\n",a[i]-1,b[i]-1,ct); } } void dich(int l,int r) { if(l>r) return; int mid=(l+r)>>1,t=check(mid); if(t==L) { print(mid); exit(0); } if(t>L) dich(l,mid-1); else dich(mid+1,r); } signed main() { n=read();m=read();L=read();s=read()+1;t=read()+1; for(int i=1;i<=m;i++) { a[i]=read()+1;b[i]=read()+1;c[i]=read(); if(c[i]==0) tag[i]=++cnt,c[i]=1; } dich(0,L*m); puts("NO"); }