zoukankan      html  css  js  c++  java
  • P5304 [GXOI/GZOI2019]旅行者 最短路+位运算优化

    题意:

    给定一张(n)个点,(m)条有向边的图,标记其中(k)个点,求这(k)个点之间的两两最短路的最小值

    范围&性质:(1le k, nle 10^5,1le mle 5 imes 10^5)

    分析:

    • 暴力

    暴力将关键点分成(A,B)两个集合,超级源向(A)集合每一个点连一条边权为0的边,(B)集合每一个点向超级汇连一条边权为(0)的边,然后从超级源向超级汇跑最短路

    • 正解

    我们发现暴力枚举的复杂度不太对,然后我们考虑优化,我们发现正解对应的(st,ed)他们的编号必定存在一位不一样,那么我们就枚举二进制位,将这位按照0和1划分成两个集合跑最短路,复杂度(O(nlog^2_n))

    代码:

    #include<bits/stdc++.h>
    #define mk(x,y) make_pair(x,y)
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 1e5+5;
    	const int maxm = 5e5+5;
    	int head[maxn],key[maxn],ghead[maxn];
    	long long dis[maxn];
    	int n,cnt=0,t,st,ed,gcnt,m,k;
    	bool vis[maxn];
    	
    	struct edge
    	{
    		int to,nxt,val;
    	}e[maxm+maxn];
    	
    	void add(int u,int v,int w)
    	{
    		e[++cnt].to=v;
    		e[cnt].val=w;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	void addedge(int u,int v,int w)
    	{
    		e[++gcnt].to=v;
    		e[gcnt].val=w;
    		e[gcnt].nxt=ghead[u];
    		ghead[u]=gcnt;
    	}
    	
    	long long dijkstra()
    	{
    		memset(dis,0x3f,sizeof(dis));
    		memset(vis,false,sizeof(vis));
    		dis[st]=0;
    		priority_queue<pair<long long,int> > q;
    		q.push(mk(0,st));
    		while(!q.empty())
    		{
    			int u=q.top().second;q.pop();
    			if(vis[u]) continue;
    			vis[u]=true;
    			for(int i=ghead[u];i;i=e[i].nxt)
    			{
    				int v=e[i].to;
    				if(dis[v]>dis[u]+e[i].val)
    				{
    					dis[v]=dis[u]+e[i].val;
    					q.push(mk(-dis[v],v));
    				}
    			}
    		}
    		return dis[ed];
    	}
    	
    	void work()
    	{
    		int a,b,c;
    		scanf("%d",&t);
    		while(t--)
    		{
    			cnt=0;
    			memset(head,0,sizeof(head));
    			scanf("%d%d%d",&n,&m,&k);
    			for(int i=1;i<=m;i++)
    			{
    				scanf("%d%d%d",&a,&b,&c);
    				add(a,b,c);
    			}
    			for(int i=1;i<=k;i++) scanf("%d",&key[i]);
    			long long ans=LLONG_MAX;
    			st=n+1;ed=n+2;
    			for(int i=0;(1<<i)<=n;i++)
    			{
    				memcpy(ghead,head,sizeof(head));
    				gcnt=cnt;
    				for(int j=1;j<=k;j++)
    				{
    					if(j&(1<<i))
    					{
    						addedge(st,key[j],0);
    					}
    					else
    					{
    						addedge(key[j],ed,0);
    					}
    				}
    				ans=min(ans,dijkstra());
    				
    				memcpy(ghead,head,sizeof(head));
    				gcnt=cnt;
    				for(int j=1;j<=k;j++)
    				{
    					if(j&(1<<i))
    					{
    						addedge(key[j],ed,0);
    					}
    					else
    					{
    						addedge(st,key[j],0);
    					}
    				}
    				ans=min(ans,dijkstra());
    			}
    			printf("%lld
    ",ans);
    		}
    	
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    R语言爬虫:CSS方法与XPath方法对比(代码实现)
    R语言爬虫:Rvest包函数介绍(表格)
    R语言爬虫:使用R语言爬取豆瓣电影数据
    R语言学习笔记(二十二):字符串处理中的函数对比(代码实现)
    R语言学习笔记(二十一):字符串处理中的元字符(代码展示)
    history命令详解
    文件服务器:FTP服务器详解
    Linux下的DOS攻击
    Linux-/proc目录简介
    Linux-详解inode节点
  • 原文地址:https://www.cnblogs.com/youth518/p/13849560.html
Copyright © 2011-2022 走看看