1. 程式人生 > >福慧雙修(both)

福慧雙修(both)

names none 它的 printf ostream 之間 using mem 路徑

福慧雙修(both)
題目描述:
菩薩為行,福慧雙修,智人得果,不忘其本。
——唐·慧立《大慈恩寺三藏法師傳》
有才而知進退,福慧雙修,這才難得。
——烏雅氏
如何福慧雙修?被太後教導的甄嬛徘徊在禦花園當中。突然,她發現禦花園中的花朵全都是紅色和藍色的。她冥冥之中得到了響應:這就是指導她如何福慧雙修的!現在禦花園可以看作是有N塊區域,M條小路,兩塊區域之間可通過小路連接起來。現在甄嬛站在1號區域,而她需要在禦花園中繞一繞,且至少經過1個非1號區域的區域。但是恰好1號區域離碎玉軒最近,因此她最後還是要回到1號區域。由於太後教導她要福慧雙修,因此,甄嬛不能走過任何一條她曾經走過的路。但是,禦花園中來往的奴才們太多了,而且奴才們前行的方向也不一樣,因此甄嬛在走某條小路的時候,方向不同所花的時間不一定一樣。天色快暗了,甄嬛需要盡快知道至少需要花多少時間才能學會如何福慧雙修。如果甄嬛無法達到目的,輸出“-1”。

輸入格式:
第一行僅2個正整數n,m,意義如題。
接下來m行每行4個正整數s,t,v,w,其中s,t為小路所連接的兩個區域的編號,v為甄嬛從s到t所需的時間,w為甄嬛從t到s所需的時間。數據保證無重邊。

輸出格式:
僅一行,為甄嬛回到1號區域所需的最短時間,若方案不存在,則輸出-1

樣例輸入:
樣例一
3 3
1 2 2 3
2 3 1 4
3 1 5 2
樣例二
3 2
1 2 1 1
2 3 1 2

樣例輸出:
樣例一
8
樣例二
-1

數據範圍:
對於40%的數據:n<=1,000; m<=5,000
對於100%的數據:1<=n<=40,000; 1<=m<=100,000; 1<=v,w<=1,000

時間限制:
1s

空間限制:
256M

不得不說,這題很難想,隨便亂打了一個DFS也沒有拿到分...(菜啊)正解很鬼畜,想都想不到.
首先,我們肯定要跑一遍spfa,求出每一個點到1的最短距離dis[i].
接下來,我們要用到一個數組,這個數組非常的重要,設pre[i]表示這條路徑上與1相連的點的標號。這樣我們就可以通過這個pre數組推測出一條邊是否已被使用.
顯然,在spfa後只有直接與1相連的點的pre值為其本身,其他的點的pre值都等於其前驅節點的pre值.
由於最後題目讓我們回到點1,所以,我們需要建立一個新圖,將匯點變為n+1,同時,要在原圖的基礎上改一下,建一個新圖.
那麽,我們要通過pre數組來搞事情了:

a.如果有一條從1到x的邊,邊權為w:
1.若pre[x]!=x
說明從1到x的最短路沒有經過這條邊,這條邊可以在新圖中建立,邊權為w.
2.若pre[x]==x
說明從1到x的最短路通過這條邊,這條邊不能建立.
因為,我們將會用這條比較優秀的邊去建立新圖的邊,這樣,如果建了這條邊,這條邊可能會被用2次或更多.
b.如果有一條從x到1的邊,邊權為w:
1.若pre[x]!=x
說明從1到x的最短路沒有經過這條邊,這條邊的可以被建立,因此我們可以等效地在新圖中建立一條從起點1到終點n+1的邊,邊權為w+dis[x]
2.若pre[x]==x
說明從1到x的最短路通過了這條邊,我們把這條邊等效轉移一下,從x->1變為x->n+1,邊權為w.
c.如果有一條起終點均不為1的邊,邊權為w.
1.若pre[u]!=pre[v],說明原點到達這兩端點,經過的最短路徑是不同的.
什麽意思呢?就是說邊對於u和v並沒有用過,所以我們可以在新圖中建立一條從1到v,邊權為dis[u]+w的邊(當然原邊都要刪除).
2.若pre[u]==pre[v],在新圖中保留原邊就行了,不要動它(它並沒有做什麽壞事啊qwq)。
註意,新圖建好後,需要把dis數組重新初始化,因為dis數組已經在建圖時已經發揮了它的作用,現在它就可以滾粗了...
最後,只要在新圖中再跑一次spfa,輸出dis[n+1]就好啦.

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<queue>
 6 #define nnxt New_nxt
 7 #define nson New_son
 8 #define nw New_w
 9 #define nlnk New_lnk
10 using namespace std;
11 const int maxe=200005,maxn=40005;
12 int n,m,tot,ntot,ans;
13 int nxt[maxe],son[maxe],w[maxe],lnk[maxn];
14 int nnxt[maxe],nson[maxe],nw[maxe],nlnk[maxn];
15 int dis[maxn],pre[maxn];
16 bool vis[maxn];
17 int read(){
18     int x=0; char ch=getchar();
19     while (ch<0||ch>9) ch=getchar();
20     while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
21     return x;
22 }
23 void add(int x,int y,int z){nxt[++tot]=lnk[x],son[tot]=y,w[tot]=z,lnk[x]=tot;}
24 void addn(int x,int y,int z){nnxt[++ntot]=nlnk[x],nson[ntot]=y,nw[ntot]=z,nlnk[x]=ntot;}
25 void spfa(){
26     memset(vis,0,sizeof vis),vis[1]=1;
27     memset(dis,63,sizeof dis),dis[1]=0;
28     memset(pre,0,sizeof pre),pre[1]=1;
29     int x; queue <int> Q; while (!Q.empty()) Q.pop(); Q.push(1);
30     while (!Q.empty()){
31         vis[x=Q.front()]=0,Q.pop();
32         for (int j=lnk[x]; j; j=nxt[j])
33         if (dis[son[j]]>dis[x]+w[j]){
34             dis[son[j]]=dis[x]+w[j]; pre[son[j]]=pre[x];
35             if (x==1) pre[son[j]]=son[j];
36             if (!vis[son[j]]) vis[son[j]]=1,Q.push(son[j]);
37         }
38     }
39 }
40 void spfa_new(){
41     memset(vis,0,sizeof vis),vis[1]=1;
42     memset(dis,63,sizeof dis),dis[1]=0;
43     int x; queue <int> Q; while (!Q.empty()) Q.pop(); Q.push(1);
44     while (!Q.empty()){
45         vis[x=Q.front()]=0,Q.pop();
46         for (int j=nlnk[x]; j; j=nnxt[j])
47         if (dis[nson[j]]>dis[x]+nw[j]){
48             dis[nson[j]]=dis[x]+nw[j];
49             if (!vis[nson[j]]) vis[nson[j]]=1,Q.push(nson[j]);
50         }
51     }
52 }
53 int main(){
54     n=read(),m=read(),tot=ntot=0,ans=1e9;
55     for (int i=1; i<=m; i++){
56         int x=read(),y=read(),z1=read(),z2=read();
57         add(x,y,z1),add(y,x,z2);
58     }
59     spfa();
60     for (int i=1; i<=n; i++)
61         for (int j=lnk[i]; j; j=nxt[j])
62         if (i==1){
63             if (pre[son[j]]!=son[j]) addn(1,son[j],w[j]);
64         }else
65         if (son[j]==1){
66             if (pre[i]==i) addn(i,n+1,w[j]); else addn(1,n+1,w[j]+dis[son[j]]);
67         }else{
68             if (pre[i]!=pre[son[j]]) addn(1,son[j],dis[i]+w[j]); else addn(i,son[j],w[j]);
69         }
70     spfa_new();
71     if (dis[n+1]!=dis[0]) printf("%d",dis[n+1]); else puts("-1");
72     return 0;
73 }
View Code

福慧雙修(both)