zoukankan      html  css  js  c++  java
  • 【洛谷P5304】旅行者

    题目

    题目链接:https://www.luogu.com.cn/problem/P5304
    J 国有 \(n\) 座城市,这些城市之间通过 \(m\) 条单向道路相连,已知每条道路的长度。

    一次,居住在 J 国的 Rainbow 邀请 Vani 来作客。不过,作为一名资深的旅行者,Vani 只对 J 国的 \(k\) 座历史悠久、自然风景独特的城市感兴趣。
    为了提升旅行的体验,Vani 想要知道他感兴趣的城市之间「两两最短路」的最小值(即在他感兴趣的城市中,最近的一对的最短距离)。

    也许下面的剧情你已经猜到了——Vani 这几天还要忙着去其他地方游山玩水,就请你帮他解决这个问题吧。

    思路

    考虑将他喜欢的点拆成两部分,容易在 \(O(n\log n)\) 复杂度内求出一个集合的点到另一个集合的点的距离。
    所以我们只需要拆分若干次,似的两个点至少在一次拆分中属于不同的集合。
    那么可以按二进制下 0 和 1 来拆分,枚举二进制下每一位,这一位是 \(1\) 则扔到第一个集合中,如果是 \(0\) 则扔到第 \(2\) 个集合中。
    时间复杂度 \(O(n\log^2 n)\)

    代码

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    
    const int N=100010,M=500010;
    int Q,n,m,k,S,tot,head[N],a[N],U[M],V[M],D[M];
    ll ans,dis[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to,dis;
    }e[(M+N)*2];
    
    void add(int from,int to,int d)
    {
    	e[++tot].to=to;
    	e[tot].dis=d;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void prework()
    {
    	memset(head,-1,sizeof(head));
    	tot=0; ans=1000000000000000000LL;
    }
    
    void dij()
    {
    	priority_queue<pair<ll,int> > q;
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[S]=0; q.push(mp(0,S));
    	while (q.size())
    	{
    		int u=q.top().second; q.pop();
    		if (vis[u]) continue;
    		vis[u]=1;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (dis[v]>dis[u]+e[i].dis)
    			{
    				dis[v]=dis[u]+e[i].dis;
    				q.push(mp(-dis[v],v));
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d",&Q);
    	S=N-1;
    	while (Q--)
    	{
    		prework();
    		scanf("%d%d%d",&n,&m,&k);
    		for (int i=1,x,y,z;i<=m;i++)
    		{
    			scanf("%d%d%d",&x,&y,&z);
    			add(x,y,z);
    		}
    		for (int i=1;i<=k;i++)
    			scanf("%d",&a[i]);
    		for (int i=0;(1<<i)<=k;i++)
    		{
    			int id=(1<<i);
    			head[S]=-1; tot=2*m;
    			for (int j=1;j<=k;j++)
    				if (j&id) add(S,a[j],0);
    			dij();
    			for (int j=1;j<=k;j++)
    				if (!(j&id)) ans=min(ans,dis[a[j]]);
    			
    			head[S]=-1; tot=2*m;
    			for (int j=1;j<=k;j++)
    				if (!(j&id)) add(S,a[j],0);
    			dij();
    			for (int j=1;j<=k;j++)
    				if (j&id) ans=min(ans,dis[a[j]]);
    		}
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    zookeeper的集群搭建
    Java代码操作zookeeper
    zookeeper的简介和相关命令操作
    Linux上搭建zookeeper服务注册中心
    Java8新特性(三)之方法引用和构造器引用
    Java8新特性(一)之Lambda表达式
    react-navigation 3.x版本的使用
    react-navigation 3.x版本的安装以及react-native-gesture-handler配置
    react-native 打包 出apk
    webpack的使用
  • 原文地址:https://www.cnblogs.com/stoorz/p/13784674.html
Copyright © 2011-2022 走看看