福慧双修(both)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了福慧双修(both)相关的知识,希望对你有一定的参考价值。

福慧双修(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)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4398:福慧双修

bzoj4398: 福慧双修

BZOJ2407/4398探险/福慧双修 最短路建模

不会的图论题

SciKit-Learn & TensorFlow与吴恩达机器学习双修笔记——创建工作区

C语言高手都是双修,在语法层面几乎都是朴实无华,从不炫技,人家炫的是思想