藍書(演算法競賽進階指南)刷題記錄——poj3662 Telephone Lines
阿新 • • 發佈:2018-12-14
題目大意:找一條從1到n的路徑,使得這條路徑上第k+1大的邊最小.
解法一:
我們可以假裝這是一張有向無環圖DAG,那麼我們就可以設計一個DP陣列f[i][j]表示達到第i個點時免費維修了j條邊的最小代價.
那麼我們就可以發現方程即為:
.
但是這不是一張有向無環圖,具有後效性,我們並不能這麼跑一個DP.
所以我們用最短路代替DP,解決後效性的問題.
於是我們可以使用SPFA來做這道題,時間複雜度,其中若不特殊構造資料,則e為一個較小的常數.
程式碼如下:
//#include<bits/stdc++.h> #include<iostream> #include<queue> using namespace std; #define Abigail inline void const int N=1000,M=10000; const int INF=(1<<30)-1; int n,m,k; struct side{ int y,next,v; }e[M*2+9]; int lin[N+9],top; struct state{ int node,use; }; queue<state>q; int dis[N+9][M+9]; bool use[N+9][M+9]; void ins(int x,int y,int v){ e[++top].y=y;e[top].v=v; e[top].next=lin[x]; lin[x]=top; } state make_state(int x,int y){ state t; t.node=x,t.use=y; return t; } void spfa(int sp,int sk){ for (int i=1;i<=n;i++) for (int j=0;j<=k;j++) dis[i][j]=INF; q.push(make_state(sp,sk)); dis[sp][sk]=0; use[sp][sk]=1; while (!q.empty()){ state t=q.front(); q.pop();use[t.node][t.use]=0; for (int i=lin[t.node];i;i=e[i].next){ if (max(dis[t.node][t.use],e[i].v)<dis[e[i].y][t.use]){ dis[e[i].y][t.use]=max(dis[t.node][t.use],e[i].v); if (!use[e[i].y][t.use]){ //這裡不能用continue代替,否則下面的語句就不會執行 use[e[i].y][t.use]=1; q.push(make_state(e[i].y,t.use)); } } if (t.use<k&&dis[t.node][t.use]<dis[e[i].y][t.use+1]){ dis[e[i].y][t.use+1]=dis[t.node][t.use]; if (!use[e[i].y][t.use+1]){ use[e[i].y][t.use+1]=1; q.push(make_state(e[i].y,t.use+1)); } } } } } Abigail into(){ scanf("%d%d%d",&n,&m,&k); int x,y,l; for (int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&l); ins(x,y,l);ins(y,x,l); } } Abigail work(){ spfa(1,0); } Abigail outo(){ if (dis[n][k]^INF) printf("%d\n",dis[n][k]); else printf("-1\n"); } int main(){ into(); work(); outo(); return 0; }
解法二:
我們可以很容易發現這道題中,若我們花費的錢更多時,那麼合法的方案已定越多,且已定包含花費更少的方案,所以我們發現這道題可以使用二分花費轉化為判定問題.
我們確定一個花費mid後,我們可以將大於這個花費的邊的邊權都設為1,小於的都設為0,那麼我們就可以跑一遍最短路.
由於這是0-1邊權最短路問題,所以我們可以使用一個雙端佇列BFS來進行求解.
程式碼如下:
//#include<bits/stdc++.h> #include<iostream> #include<deque> using namespace std; #define Abigail inline void typedef long long LL; const int N=1000,M=10000; const int INF=(1<<20)-1; int n,m,k; struct side{ int y,next,v,use; }e[M*2+9]; int top,lin[N+9]; int dis[N+9],use[N+9],ans; deque<int>q; void ins(int x,int y,int v){ e[++top].y=y;e[top].v=v; e[top].next=lin[x]; lin[x]=top; } bool check(int mid){ for (int i=1;i<=top;i++) e[i].use=e[i].v>mid?1:0; for (int i=1;i<=n;i++) use[i]=0,dis[i]=INF; dis[1]=0;use[1]=1; q.push_back(1); while (!q.empty()){ int t=q.front(); q.pop_front();use[t]=2; for (int i=lin[t];i;i=e[i].next) if (dis[t]+e[i].use<dis[e[i].y]){ dis[e[i].y]=dis[t]+e[i].use; if (use[e[i].y]) continue; use[e[i].y]=1; if (e[i].use) q.push_back(e[i].y); else q.push_front(e[i].y); } } return dis[n]<=k; } Abigail into(){ scanf("%d%d%d",&n,&m,&k); int x,y,v; for (int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&v); ins(x,y,v);ins(y,x,v); } } Abigail work(){ ans=INF; for (int i=19;i>=0;i--) if (check(ans-(1<<i))) ans-=1<<i; } Abigail outo(){ printf("%d\n",ans^INF?ans:-1); } int main(){ into(); work(); outo(); return 0; }