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

首先比较好想的是断边跑dij,虽然能过(数据太水),但是可以被菊花图给卡掉。

那我们就考虑怎样可以降低复杂度,图论唯一能优化的应该就是建图了吧。

这里我们就可以进行分组最短路,通过二进制来确保分组的正确性,因为任意两个不同的点,二进制一定至少存在一位不同。于是我们以每个二进制位的0,1进行分组,每组点组成的环至少被更新一次。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+107;
int n,m,e,f;


int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}


int h[N<<1],to[N],nxt[N],w[N],tot;
void add(int x,int y,int dt)
{
	to[++tot]=y;
	nxt[tot]=h[x];
	w[tot]=dt;
	h[x]=tot;
}

priority_queue<pair<int,int>>q;
bool vis[N];
int dis[N];
void dij(int x)
{
	memset(dis,0x3f,sizeof dis);
	memset(vis,0,sizeof vis);
	dis[x]=0;
	q.push(make_pair(-dis[x],x));
	while(!q.empty())
	{
		// cout<<"!!";
		x=q.top().second;
		q.pop();
		if(x==f) return ;
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=h[x];i;i=nxt[i])
		{
			int y=to[i];
			// vis[y]=1;
			if(dis[y]>dis[x]+w[i])
			{
				dis[y]=dis[x]+w[i];
				if(!vis[y])
				{
					q.push(make_pair(-dis[y],y));
				}
			}
		}
	}
}

int cnt;
struct lmy
{
	int y,w;
}c[N];

void clear()
{
	memset(h,0,sizeof h);
	tot=2; cnt=0;
}



int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);

	int T=read();
	while(T--)
	{
		clear();
		int ans=0x3f3f3f3f;
		n=read(),m=read();
		for(int i=1;i<=m;i++)
		{
			int x=read(),y=read(),dt=read();
			if(x>y) swap(x,y);
			if(x==1) c[++cnt]={y,dt};
			else add(x,y,dt),add(y,x,dt);

		}
		int z=n;
		for(int i=1;i<=n;i<<=1)
		{
			e=++z,f=++z;
			for(int j=1;j<=cnt;j++)
			{
				if(c[j].y&i) add(e,c[j].y,c[j].w);
				else add(c[j].y,f,c[j].w);
			}
			dij(e);
			ans=min(ans,dis[f]);
		}
		if(ans==0x3f3f3f3f) ans=-1;
		printf("%d\n",ans);

	}
	return 0;
}
posted @ 2024-08-13 14:51  zhengchenxi  阅读(21)  评论(0编辑  收藏  举报