zoukankan      html  css  js  c++  java
  • [bzoj2407]探险——重构图+最短路

    题目大意:

    给定一个无向图,每一条边正着和反着都有一个边权,求一条不经过重复边的路径,使得边权和最小。

    思路:

    这个题目的思路比较巧妙
    网络上的题解只有做法,没有详细地解释。
    考虑最暴力的方法,对于1号点能够直接到达的每一个点,把它和1号点的边删掉以后,以这个点为源点跑最短路。
    但是这样会T飞。
    不妨先放下不能重复走的限制,建立一个新的虚拟汇点t=n+1,然后将所有连向1的边转化成连向t的边。然后对于1到t跑最短路算法
    这样子做显然有一些点问题,有的路径可能刚刚才走出去就又回来了,这样是不合法的。
    例如一条边(1,v,w),在转移中可能会是这个样子的 (1->v->t)
    那么如果我们将(1,v,w)给去掉,将可能从(1,v,w)这条边出发的路径转化为一些边(1,u,dis[1...u]) (1,v,w)(in) this path
    使得这些u存在于所有(1->t)的路径上,并且对于所有的u,都有1到u的最短路的第一个点不是v。
    这样以后我们再去求最短路,便不用担心一条边跑出去再跑回去的问题,因为有了上面的限制,通过这条边出去之后再回去一定不是最短的。
    虑怎么建立上面所说的等效边,可以对于原图做一次最短路,记录每个点的最短路径的第一个点f[u],枚举每一条边(u,v,w),如果f[u]!=f[v],那么则说明这是f[u]和f[v]的范围的分界处,在这里分别对f[u]和f[v]都建立等效边即可。
    当然如果u=1或者v=1的情况需要特殊考虑,但是方法是类似的。具体方法可以参考hzwer的博客。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mk make_pair
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj2407.in","r",stdin);
    	freopen("bzoj2407.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	T __=0,mul=1; char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')mul=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    	_=__*mul;
    }
    
    const int maxn=1e4+10;
    const int maxm=2e5+10;
    int n,m,dis[maxn],fr[maxn];
    int beg[maxn],from[maxm<<1],to[maxm<<1],las[maxm<<1],w[maxm<<1],cnte=1;
    priority_queue< pii,vector<pii>,greater<pii> >qu;
    
    void add(int u,int v,int val){
    	las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; from[cnte]=u; w[cnte]=val;
    }
    
    void Dijkstra(){
    	memset(dis,63,sizeof(dis));
    	memset(fr,0,sizeof(fr));
    	dis[1]=0; qu.push(mk(0,1));
    	while(!qu.empty()){
    		int u=qu.top().se,d=qu.top().fi;
    		qu.pop();
    		if(d!=dis[u])continue;
    		for(int i=beg[u];i;i=las[i]){
    			int v=to[i];
    			if(d+w[i]<dis[v]){
    				fr[v]= u==1 ? i/2 : fr[u];
    				dis[v]=d+w[i];
    				qu.push(mk(dis[v],v));
    			}
    		}
    	}
    }
    
    void rebuild(){
    	int sz=cnte; cnte=0;
    	memset(beg,0,sizeof(beg));
    	REP(i,2,sz){
    		if(from[i]==1){
    			if(fr[to[i]]!=i/2)
    				add(from[i],to[i],w[i]);
    		}
    		else if(to[i]==1){
    			if(fr[from[i]]==i/2)
    				add(from[i],n+1,w[i]);
    			else add(1,n+1,dis[from[i]]+w[i]);
    		}
    		else{
    			if(fr[from[i]]==fr[to[i]])
    				add(from[i],to[i],w[i]);
    			else add(1,to[i],dis[from[i]]+w[i]);
    		}
    	}
    }
    
    int main(){
    	File();
    	read(n); read(m);
    	int u,v,val0,val1;
    	REP(i,1,m){
    		read(u),read(v),read(val0),read(val1);
    		add(u,v,val0),add(v,u,val1);
    	}
    	Dijkstra();
    	rebuild();
    	Dijkstra();
    	printf("%d
    ",dis[n+1]);
    	return 0;
    }
    
    
  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/ylsoi/p/9861095.html
Copyright © 2011-2022 走看看