首先比较好想的是断边跑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;
}