zoukankan      html  css  js  c++  java
  • 那一天她离我而去 二进制分组建图

    那一天她离我而去 二进制分组建图

    题目描述

    她走的悄无声息,消失的无影无踪。

    至今我还记得那一段时间,我们一起旅游,一起游遍山水。到了最
    终的景点,她却悄无声息地消失了,只剩我孤身而返。

    现在我还记得,那个旅游区可以表示为一张由(n)个节点(m)条边组成无向图。

    我故地重游,却发现自己只想尽快地结束这次旅游。我从景区的出发点(即 (1) 号节点)出发,却只想找出最短的一条回路重新回到出发点,并且中途不重复经过任意一条边。
    即:我想找出从出发点到出发点的小环。

    输入格式

    每个测试点有多组测试数据
    第一行有一个正整数(T,(T leq 10))
    表示数据组数
    接下来对于每组数据,第一行有两个正整数(n,m,(n leq 10 ^4,m leq 4 imes 10^4)) 分别代表图的点数和边数
    接下来有(m)行,每行三个整数 (u,v,d)表示(u,v)之间存在一条长度为(d,(d leq 10^3))的路径
    保证不存在重边,自环。

    输出格式

    对于每组测试数据,输出题目中所求的最小环的长度。
    无解输出 (-1)

    样例

    样例输入

    2
    3 3
    1 2 1
    2 3 1
    3 1 1
    4 5
    1 2 2
    2 3 2
    3 4 2
    1 4 2
    1 3 5

    样例输出

    3
    8

    数据范围与提示

    对于(30\%)的数据,(n leq 10^3,mleq 4 imes 10^3)
    对于另外(30\%)的数据,(n leq 10^4,m=n)
    对于(100\%)的数据,(n leq 10^4,mleq 5 imes 10^4)

    分析

    一个暴力的思路是,将所有与起点相连的边删除,从这些相连的点跑到其他相连点的最短路尝试更新答案。
    可以尝试优化这个暴力思路。
    发现这个算法有一部分冗余,我们可以分组进行最短路。
    因为任意两个不同的点,二进制一定至少存在一位不同。
    我们以每个二进制位的(0),(1)进行分组,每组点组成的环一定被至少一次更新,于是可以达到目的。
    复杂度 (O(m log^2n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    inline int read(){
    	int x=0,fh=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=2e5+5;
    int t,head[maxn],tot=2,n,m,cnt,qd,zd;
    struct asd{
    	int to,next,val;
    }b[maxn];
    void ad(int aa,int bb,int cc){
    	b[tot].to=bb;
    	b[tot].next=head[aa];
    	b[tot].val=cc;
    	head[aa]=tot++;
    }
    struct jie{
    	int num,jl;
    	jie(){}
    	jie(int aa,int bb){
    		num=aa,jl=bb;
    	}
    	bool operator < (const jie& A)const{
    		return jl>A.jl;
    	}
    };
    bool vis[maxn];
    int dis[maxn];
    void dij(int qd){
    	std::priority_queue<jie> q;
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[qd]=0;
    	q.push(jie(qd,0));
    	while(!q.empty()){
    		int now=q.top().num;
    		q.pop();
    		if(now==zd) return;
    		if(vis[now]) continue;
    		vis[now]=1;
    		for(int i=head[now];i!=-1;i=b[i].next){
    			int u=b[i].to;
    			if(dis[u]>dis[now]+b[i].val){
    				dis[u]=dis[now]+b[i].val;
    				q.push(jie(u,dis[u]));
    			}
    		}
    	}
    }
    struct jl{
    	int bh,jz;
    	jl(){}
    	jl(int aa,int bb){
    		bh=aa,jz=bb;
    	}
    }c[maxn];
    int main(){
    	freopen("leave.in","r",stdin);
    	freopen("leave.out","w",stdout);
    	t=read();
    	while(t--){
    		memset(head,-1,sizeof(head));
    		memset(&b,0,sizeof(b));
    		memset(&c,0,sizeof(c));
    		tot=2,cnt=0;
    		n=read(),m=read();
    		for(int i=1;i<=m;i++){
    			int aa,bb,cc;
    			aa=read(),bb=read(),cc=read();
    			if(aa>bb) std::swap(aa,bb);
    			if(aa==1) c[++cnt]=jl(bb,cc);
    			else {
    				ad(aa,bb,cc);
    				ad(bb,aa,cc);
    			}
    		}
    		int nans=0x3f3f3f3f,nn=n;
    		for(int i=1;i<=n;i<<=1){
    			qd=++nn,zd=++nn;
    			for(int j=1;j<=cnt;j++){
    				if(c[j].bh&i) ad(qd,c[j].bh,c[j].jz);
    				else ad(c[j].bh,zd,c[j].jz);
    			}
    			dij(qd);
    			nans=std::min(nans,dis[zd]);
    		}
    		if(nans==0x3f3f3f3f) printf("-1
    ");
    		else printf("%d
    ",nans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    2019-9-2-Visual-Studio-自定义项目模板
    2018-8-10-WPF-判断调用方法堆栈
    2018-8-10-WPF-判断调用方法堆栈
    2018-8-10-VisualStudio-自定义外部命令
    2018-8-10-VisualStudio-自定义外部命令
    Java实现 LeetCode 999 车的可用捕获量(简单搜索)
    向代码致敬,寻找你的第83行(阿里巴巴的第83行代码是什么梗)
    向代码致敬,寻找你的第83行(阿里巴巴的第83行代码是什么梗)
    向代码致敬,寻找你的第83行(阿里巴巴的第83行代码是什么梗)
    Java实现 LeetCode 557 反转字符串中的单词 III(StringBuilder的翻转和分割)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13615770.html
Copyright © 2011-2022 走看看