zoukankan      html  css  js  c++  java
  • 【BZOJ1880】[Sdoi2009]Elaxia的路线(最短路)

    【BZOJ1880】[Sdoi2009]Elaxia的路线(最短路)

    题面

    BZOJ
    洛谷

    题解

    假装我们知道了任意两点间的最短路,那么我们怎么求解答案呢?
    不难发现公共路径一定是一段连续的路径(如果不连续那么显然可以把中间分开的那段变成一样路径)。
    这样子我们只需要(O(n^2))枚举这个路径的起点和终点(check)一下就可以知道答案了。
    然而并没有办法求任意两点之间的最短路,因为这样子是(O(n^3))的。并不要认为对于每个点跑一遍最短路就行了,(SPFA)不说了,它死了。(Dijkstra)的复杂度是(O((n+m)logm))的,如果(m=n^2)还不如(Floyd)
    大概的代码如下,我是对于每一个点跑了一遍(Dij)(雾

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 1550
    #define pi pair<int,int>
    #define mp make_pair
    #define fr first
    #define sd second
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Line{int v,next,w;}e[MAX*MAX*2];
    int h[MAX],cnt=1;
    inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    int dis[MAX][MAX];
    int n,m,S1,S2,T1,T2,ans;
    bool vis[MAX];
    void SPFA(int S,int *dis)
    {
    	for(int i=1;i<=n;++i)dis[i]=1e9,vis[i]=false;
    	priority_queue<pi,vector<pi>,greater<pi> > Q;
    	Q.push(mp(0,S));dis[S]=0;
    	while(!Q.empty())
    	{
    		pi u=Q.top();Q.pop();
    		if(vis[u.sd])continue;vis[u.sd]=true;
    		for(int i=h[u.sd];i;i=e[i].next)
    			if(dis[e[i].v]>u.fr+e[i].w)
    			{
    				dis[e[i].v]=u.fr+e[i].w;
    				Q.push(mp(dis[e[i].v],e[i].v));
    			}
    	}
    }
    int Dis1(int i,int j){return dis[S1][i]+dis[i][j]+dis[j][T1];}
    int Dis2(int i,int j){return dis[S2][i]+dis[i][j]+dis[j][T2];}
    int main()
    {
    	n=read();m=read();
    	S1=read(),T1=read(),S2=read(),T2=read();
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read(),w=read();
    		Add(u,v,w);Add(v,u,w);
    	}
    	for(int i=1;i<=n;++i)SPFA(i,dis[i]);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			if(i!=j)
    			{
    				if(Dis1(i,j)>dis[S1][T1]&&Dis1(j,i)>dis[S1][T1])continue;
    				if(Dis2(i,j)>dis[S2][T2]&&Dis2(j,i)>dis[S2][T2])continue;
    				ans=max(ans,dis[i][j]);
    			}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    首先,对于钦定的起点,我们到达终点一定是沿着最短路径(DAG)移动,那么我们考虑对于起点构建最短路径(DAG),将几个(DAG)重叠之后显然是要求的是(S1 ightarrow T1)的一条路径上的最长的、在两个最短路径(DAG)中都出现过的链。
    那么我们把同时出现在两个(DAG)中的边全部拿出来建图,跑一个(DAG)上最长链就好了。
    我代码写的有点冗长。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 1550
    #define pi pair<int,int>
    #define mp make_pair
    #define fr first
    #define sd second
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Line{int v,next,w;}e[1000000];
    int h[MAX],cnt=2,dg[MAX];
    inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    vector<int> E[MAX],W[MAX];
    int dis[MAX][MAX];
    int n,m,S1,S2,T1,T2,ans;
    bool vis[MAX];
    void SPFA_heap(int S,int *dis)
    {
    	for(int i=1;i<=n;++i)dis[i]=1e9,vis[i]=false;
    	priority_queue<pi,vector<pi>,greater<pi> > Q;
    	Q.push(mp(0,S));dis[S]=0;
    	while(!Q.empty())
    	{
    		pi u=Q.top();Q.pop();
    		if(vis[u.sd])continue;vis[u.sd]=true;
    		for(int i=h[u.sd];i;i=e[i].next)
    			if(dis[e[i].v]>u.fr+e[i].w)
    			{
    				dis[e[i].v]=u.fr+e[i].w;
    				Q.push(mp(dis[e[i].v],e[i].v));
    			}
    	}
    }
    int S[MAX],f[MAX],top;
    void Topsort()
    {
    	queue<int> Q;
    	for(int i=1;i<=n;++i)if(!dg[i])Q.push(i);
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();S[++top]=u;
    		for(int i=0,l=E[u].size();i<l;++i)
    			if(!--dg[E[u][i]])Q.push(E[u][i]);
    	}
    	for(int i=top;i;--i)
    		for(int j=0,l=E[S[i]].size();j<l;++j)
    			f[S[i]]=max(f[S[i]],f[E[S[i]][j]]+W[S[i]][j]);
    	for(int i=1;i<=top;++i)ans=max(ans,f[S[i]]);
    }
    int main()
    {
    	n=read();m=read();
    	S1=read(),T1=read(),S2=read(),T2=read();
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read(),w=read();
    		Add(u,v,w);Add(v,u,w);
    	}
    	SPFA_heap(S1,dis[S1]);SPFA_heap(T1,dis[T1]);SPFA_heap(S2,dis[S2]);SPFA_heap(T2,dis[T2]);
    	for(int u=1;u<=n;++u)
    		for(int i=h[u];i;i=e[i].next)
    			if(i&1)
    			{
    				int u=e[i].v,v=e[i^1].v;
    				if(min(dis[S1][u]+dis[T1][v]+e[i].w,dis[S1][v]+dis[T1][u]+e[i].w)>dis[S1][T1])continue;
    				if(min(dis[S2][u]+dis[T2][v]+e[i].w,dis[S2][v]+dis[T2][u]+e[i].w)>dis[S2][T2])continue;
    				if(dis[S1][u]+dis[T1][v]+e[i].w==dis[S1][T1])E[u].push_back(v),W[u].push_back(e[i].w),dg[v]+=1;
    				else E[v].push_back(u),W[v].push_back(e[i].w),dg[u]+=1;
    			}
    	Topsort();
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    《A First Course in Probability》-chaper5-连续型随机变量-随机变量函数的期望
    Codeforces 837F
    Codeforces #428 Div2 D
    poj3233(等比矩阵求和)
    Codeforces #427 Div2 D
    Codeforces 837E
    hdu6086(AC 自动机)
    hdu2825(AC 自动机)
    poj2778(AC 自动机)
    Codeforces #426 Div2 D(线段树优化 DP )
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9800218.html
Copyright © 2011-2022 走看看