那一天她离我而去 (二进制分组建图)
首先比较好想的是断边跑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;
}