zoukankan      html  css  js  c++  java
  • P6880-[JOI 2020 Final]オリンピックバス【最短路】

    正题

    题目链接:https://www.luogu.com.cn/problem/P6880


    题目大意

    给出(n)个点(m)条边的有向图,边有边权和一个翻转权值。

    翻转至多一条边使得(1->n->1)往返的权值加上翻转权值最小。

    (1leq nleq 200,1leq mleq 5 imes 10^4)


    解题思路

    考虑到(n)很小可以从这个方向入手。

    有时翻转会使得最短路变长,这个时候当且仅当这条边是最短路的必经边,而图上最多有(n-1)条必经边,所以我们如果翻转必经边时直接暴力重新计算一次最短路,否则我们就用预处理的信息来计算。

    因为点很少,暴力的(dij)比堆优化快

    时间复杂度(O(n(n^2+m)))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define mp(x,y) make_pair(x,y)
    using namespace std;
    const ll N=210,M=5e4+10;
    struct node{
    	ll to,next,w,v,ban;
    }a[M<<1];
    ll n,m,tot,ls[N],f[N],g[N],F[N],G[N],ff[N],gg[N],from[N],grom[N],ans;
    bool v[N];
    void addl(ll x,ll y,ll w,ll v,ll ban){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	a[tot].v=v;a[tot].ban=ban;
    	ls[x]=tot;a[tot].w=w;
    	return;
    }
    void dij(ll *f,ll s,ll op=0){
    	memset(v,0,sizeof(v));f[s]=0;
    	for(int i=1;i<=n;i++){
    		int x=0;
    		for(int j=1;j<=n;j++)
    			if(!v[j])x=(f[j]<f[x])?j:x;
    		v[x]=1;
    		for(ll i=ls[x];i;i=a[i].next){
    			ll y=a[i].to;
    			if(a[i].ban)continue;
    			if(f[x]+a[i].w<f[y]){
    				f[y]=f[x]+a[i].w;
    				if(op==1)from[y]=i;
    				if(op==2)grom[y]=i;
    			}	
    		}
    	}
    	return;
    }
    void bij(ll *f,ll s,ll op=0){
    	memset(v,0,sizeof(v));f[s]=0;
    	for(int i=1;i<=n;i++){
    		int x=0;
    		for(int j=1;j<=n;j++)
    			if(!v[j])x=(f[j]<f[x])?j:x;
    		v[x]=1;
    		for(ll i=ls[x];i;i=a[i].next){
    			ll y=a[i].to;
    			if(!a[i].ban)continue;
    			if(f[x]+a[i].w<f[y])
    				f[y]=f[x]+a[i].w;
    		}
    	}
    	return;
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&m);tot=1;
    	for(ll i=1;i<=m;i++){
    		ll x,y,c,d;
    		scanf("%lld%lld%lld%lld",&x,&y,&c,&d);
    		addl(x,y,c,d,0);addl(y,x,c,d,1);
    	}
    	memset(f,0x3f,sizeof(f));dij(f,1,1);
    	memset(g,0x3f,sizeof(g));dij(g,n,2);
    	memset(F,0x3f,sizeof(F));bij(F,n);
    	memset(G,0x3f,sizeof(G));bij(G,1);
    	ans=f[n]+g[1];
    	for(ll x=1;x<=n;x++){
    		for(ll i=ls[x];i;i=a[i].next){
    			if(a[i].ban)continue;
    			ll y=a[i].to,w1=f[n],w2=g[1];
    			if(f[x]+a[i].w+F[y]==f[n]&&i==from[y]){
    				a[i].ban=1;a[i^1].ban=0;
    				memset(ff,0x3f,sizeof(ff));dij(ff,1);
    				w1=ff[n];a[i].ban=0;a[i^1].ban=1;
    			}
    			else w1=min(w1,f[y]+a[i].w+F[x]);
    			if(g[x]+a[i].w+G[y]==g[1]&&i==grom[y]){
    				a[i].ban=1;a[i^1].ban=0;
    				memset(gg,0x3f,sizeof(gg));dij(gg,n);
    				w2=gg[1];a[i].ban=0;a[i^1].ban=1;
    			}
    			else w2=min(w2,g[y]+a[i].w+G[x]);
    			ans=min(ans,w1+w2+a[i].v);
    		}
    	}
    	if(ans>=2e18)puts("-1");
    	else printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Maven的pom文件依赖提示 ojdbc6 Missing artifact,需要手动下载并导入maven参考
    Maven全局配置文件settings.xml详解(转)
    SpringBoot -- 项目结构+启动流程
    64匹马,8个赛道,找出前4名最少比赛多少场?——最快10次,最慢11次;
    Spring家族主流成员介绍
    java 中文与unicode互转
    Netty的Marshalling编解码器
    解决svn迁移过程中出现:SVN Error: is not the same repository as的问题
    netty入门实例
    Dubbo的使用及原理
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15040031.html
Copyright © 2011-2022 走看看