zoukankan      html  css  js  c++  java
  • BZOJ 2407: 探险/4398: 福慧双修

    2407: 探险

    Description

    探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!
    比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。
    如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?
    到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?

    Input

    第一行两个数n,m表示溶洞的数量以及暗道的数量。

    接下来m行,每行4个数s、t、w、v,表示一个暗道连接的两个溶洞s、t,这条暗道正着走(s à t)的所需要的时间w,倒着走(t à s)所需要的时间v。由于溶洞的相对位置不同,wv可能不同。

    Output

    输出一行一个数t,表示最少所需要的时间。

    Sample Input

    3 3
    1 2 2 1
    2 3 4 5
    3 1 3 2

    Sample Output

    8

    HINT

    N<=10000,M<=200000,1<=W,V<=10000

    思路:

      这题是考场上做的,只想出来了四十分做法,同届神犇suika原创本题一种不同于网上大家题解的方法,目前还没更新题解,我的做法是常规做法

    >看这里<

    我的做法是常规的最短路做法。考虑四十分 : 枚举点1周围的点,以这些点为起点向点1跑最短路,并且屏蔽掉这点到1的边,具体实现有很多种做法,在这里就不赘述了。这样做的话是O(nmlog)的(Dij)可过40分,对于满分,我们考虑这样的情况,当走出第一步之后,剩下的便是从这个点到1的最短路实现,而各个点之间会有很多重复的状态枚举,,考虑新建一张图来抛弃掉这些状态。

    我们建立汇点T=n+1 预处理出从1到各个节点的最小代价和第一步分别走了哪些点并用prev数组存下,代价用一次SPFA处理,第一步传递处理就好。

    处理好以下之后,枚举每条边进行加图,分成以下几种情况处理:

      1.该边从1到v,若prev[v] == v 不做处理,对答案产生的贡献已经记录到dis里了。

              若prev[v] != v  连接一条从1到v,代价为原代价的边

      2.该边从u到1,若pre[u] != u 直接用dis和该边val更新答案。

             否则 加一条从u到T的,权值为该边val的边

      3.该边从u到v,若u、v的prev相等,那么直接还原这条边

             否则的话,加一条从1到v,代价为f[u]+val的边

      对新图进行SPFA(DIJ)f[t]即为答案

    代码如下

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    const int inf=0x3f3f3f3f;
    const int N = 41000, M = 400010;
    using namespace std;
    int f[N],vis[N],val[M],head[N],to[M],next[M],cnt;
    int pre[N];
    int ra[M],rb[M],rc[M];
    void add_edge(int a,int b,int c) {
    	to[++cnt] = b;
    	next[cnt] = head[a];
    	head[a] = cnt;
    	val[cnt] = c;
    }
    queue<int>q;
    void spfa() {
    	while(!q.empty()) {
    		int u=q.front();
    		q.pop();
    		vis[u] = 0;
    		for(int i=head[u];i;i=next[i]) {
    			if(f[to[i]]>f[u]+val[i]) {
    				pre[to[i]]=pre[u];
    				f[to[i]]=f[u]+val[i];
    				if(!vis[to[i]]) {
    					vis[to[i]]=1;
    					q.push(to[i]);
    				}
    			}
    		}
    	}
    }
    int main() {
    	int n, m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++) {
    		int a,b,c,d;
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		add_edge(a,b,c);
    		ra[cnt]=a;
    		rb[cnt]=b;
    		rc[cnt]=c;
    		add_edge(b,a,d);
    		ra[cnt]=b;
    		rb[cnt]=a;
    		rc[cnt]=d;
    	}
    	memset(f,0x3f,sizeof(f));
    	f[1]=0;
    	for(int i=head[1];i;i=next[i]) {
    		pre[to[i]]=to[i];
    		f[to[i]]=val[i];
    		vis[to[i]]=1;
    		q.push(to[i]);
    	}
    	spfa();
    	memset(head,0,sizeof(head));
    	cnt=0;
    	int ans=0x3f3f3f3f;
    	for(int i=1;i<=2*m;i++) {
    		if(ra[i]==1) {
    			if(pre[rb[i]]!=rb[i]) add_edge(1,rb[i],rc[i]);
    		}
    		else if(rb[i]==1) {
    			if(ra[i]!=pre[ra[i]]) ans=min(ans,f[ra[i]]+rc[i]);
    			else add_edge(ra[i],n+1,rc[i]);
    		}
    		else {
    			if(pre[ra[i]]==pre[rb[i]]) {
    				add_edge(ra[i],rb[i],rc[i]);
    			}
    			else {
    				add_edge(1,rb[i],f[ra[i]]+rc[i]);
    			}
    		}
    	}
    	memset(f,0x3f,sizeof f);
    	f[1]=0;
    	q.push(1);
    	spfa();
    	ans=min(ans,f[n+1]);
    	printf("%d",ans==inf?-1:ans);
    
    }
    

     欢迎来原博客看看 >原文链接<

  • 相关阅读:
    20200209 ZooKeeper 3. Zookeeper内部原理
    20200209 ZooKeeper 2. Zookeeper本地模式安装
    20200209 Zookeeper 1. Zookeeper入门
    20200206 尚硅谷Docker【归档】
    20200206 Docker 8. 本地镜像发布到阿里云
    20200206 Docker 7. Docker常用安装
    20200206 Docker 6. DockerFile解析
    20200206 Docker 5. Docker容器数据卷
    20200206 Docker 4. Docker 镜像
    Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition
  • 原文地址:https://www.cnblogs.com/Tobichi/p/9107718.html
Copyright © 2011-2022 走看看