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

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

题目描述

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

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

现在我还记得,那个旅游区可以表示为一张由(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;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13615770.html