zoukankan      html  css  js  c++  java
  • 7201. 「JOI 2020 Final」奥运公交

    Description&Data Constraint

    对于全部数据,(2le N le 200,1le M le 5 imes 10^4,1le U_i,V_ile N,U_i ot= V_i,0le C_ile 10^6,0le D_ile 10^9)

    Solution

    首先明确一个性质,翻转的边需要在最短路树上,否则对答案没有贡献。

    首先求出 (1)(i)(i)(n) 的最短路径,并把在最短路树上的边打上标记。

    也求出 (n)(i)(i)(1) 的最短路径,同时打上最短路树的标记。

    具体操作可以建正图和反图共 (4) 个,两个正图,两个反图,正图和反图中各有一个以 (1) 为起点,一个以 (n) 为起点,以不同的起点求出对应的最短路。

    约定:

    1. (1) 为起点的正图为图 (1)。目的是求出 (1)(i) 的最短路。

    2. (n) 为起点的反图为图 (2)。目的是求出 (i)(n) 的最短路。

    3. (n) 为起点的正图为图 (3)。目的是求出 (n)(i) 的最短路。

    4. (1) 为起点的反图为图 (4)。目的是求出 (i)(1) 的最短路。

    5. 一条边的起点是 (x),终点是 (y),权值是 (v)

    令初始答案为在不翻转边下的 (1)(n)(n)(1) 的最短路径和。

    考虑枚举边,对于 (1)(n),如果该边不在图的最短路树上,就返回原值,否则将此边翻转跑最短路。

    对于翻转,显然不能找到原边将其翻转。有一种想法是给原边打上标记,加入新的翻转边并在最短路结束后将其删掉。

    另一种想法是手动走翻转边。对于一条边,要么走要么不走。不走就是在没有原边的基础上跑最短路,走则是先从 (1) 走到 (y),再从 (x) 走到 (n),同时补上中间少了的 (v)

    (1)(n)(n)(1) 分开处理,求出两个最短路,判断最短路径和加上修改当前边的权值与答案的大小,更新答案。

    最后判断 (-1),输出答案即可。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define inf 1e9
    #define N 205
    #define M 50005
    #define ll long long
    using namespace std;
    int n,m,x[M],y[M];
    ll ans,z[M],d[M];
    struct gra
    {
    	int s,tot,cant,last[M];
    	ll dis1[N],dis2[N];
    	bool bin[M],bj[N];
    	struct node
    	{
    		int to,next,head;
    		ll val;
    	}a[M];
    	void add(int x,int y,ll z)
    	{
    		a[++tot].to=y;
    		a[tot].val=z;
    		a[tot].next=a[x].head;
    		a[x].head=tot;
    	}
    	void dij()
    	{
    		memset(bj,false,sizeof(bj));
    		for (int i=1;i<=n+1;++i)
    			dis1[i]=inf;
    		dis1[s]=0;
    		for (int i=1;i<=n;++i)
    		{
    			int k=n+1;
    			for (int j=1;j<=n;++j)
    				if (!bj[j]&&dis1[j]<dis1[k]) k=j;
    			if (k==n+1) break;
    			bj[k]=true;
    			for (int j=a[k].head;j;j=a[j].next)
    			{
    				int u=a[j].to;
    				if (!bj[u]&&dis1[u]>dis1[k]+a[j].val) dis1[u]=dis1[k]+a[j].val,last[u]=j;
    			}
    		}
    		for (int i=1;i<=n;++i)
    			if (i!=s) bin[last[i]]=true;
    	}
    	void get()
    	{
    		memset(bj,false,sizeof(bj));
    		for (int i=1;i<=n+1;++i)
    			dis2[i]=inf;
    		dis2[s]=0;
    		for (int i=1;i<=n;++i)
    		{
    			int k=n+1;
    			for (int j=1;j<=n;++j)
    				if (!bj[j]&&dis2[j]<dis2[k]) k=j;
    			if (k==n+1) break;
    			bj[k]=true;
    			for (int j=a[k].head;j;j=a[j].next)
    			{
    				int u=a[j].to;
    				if (!bj[u]&&dis2[u]>dis2[k]+a[j].val&&j!=cant) dis2[u]=dis2[k]+a[j].val;
    			}
    		}
    	}
    	ll calc(int e,int ss)
    	{
    		if (!bin[e]) return dis1[ss];
    		cant=e;
    		get();
    		return dis2[ss];
    	}
    }g[10];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	g[1].s=g[4].s=1;
    	g[2].s=g[3].s=n;
    	for (int i=1;i<=m;++i)
    	{
    		scanf("%d%d%lld%lld",&x[i],&y[i],&z[i],&d[i]);
    		g[1].add(x[i],y[i],z[i]);g[2].add(y[i],x[i],z[i]);
    		g[3].add(x[i],y[i],z[i]);g[4].add(y[i],x[i],z[i]);
    	}
    	for (int i=1;i<=4;++i)
    		g[i].dij();
    	ans=g[1].dis1[n]+g[3].dis1[1];
    	for (int i=1;i<=m;++i)
    	{
    		ll d1=min(g[1].calc(i,n),g[1].calc(i,y[i])+z[i]+g[2].calc(i,x[i]));
    		ll d2=min(g[3].calc(i,1),g[3].calc(i,y[i])+z[i]+g[4].calc(i,x[i]));
    		ans=min(ans,d1+d2+d[i]);
    	}
    	if (ans>=1e9) printf("-1
    ");
    	else printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    《社区教育在线学习平台评价体系的设计研究》 文献随笔(七)
    《基于个性化推荐的在线学习系统研究与实现》 文献随笔(六)
    《基于校园网云平台微课在线学习系统的设计分析》 文献随笔(五)
    《基于微服务架构的在线学习系统设计与实现》第三章 文献随笔(四)
    《基于微服务架构的在线学习系统设计与实现》第一章节5 文献笔记(三)
    《基于Android的微课程平台设计》论文笔记(二)
    《基于Android的在线学习软件的设计与实现》论文笔记一
    在线学习系统的设计与实现 文献综述
    《基于JavaEE的全丰集团OA系统的设计与实现》论文笔记(十六)
    《电子签名技术在 OA 系统公文流转中的应用》论文笔记(十五)
  • 原文地址:https://www.cnblogs.com/Livingston/p/15041690.html
Copyright © 2011-2022 走看看