题意:
给出一个无向图,求其中包含点1的最小环。
分析:
这题方法非常的多,(因为结论非常的多)。
比较常见的结论是:最小环一定是最短路树中,不在同一个子树(即从根出发第一个点不同)的两个点之间的边+两点到1的最短距离。
最小环一定是到达某个点的最短+次短路(最短和次短也要求第一个点不同)。
最慢的反而是标算给的方法:对与根相邻的点二进制分组,每次求从一组出发,到达另一组的最短路。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define SF scanf
#define PF printf
#define MAXM 40010
#define MAXN 10010
using namespace std;
int u,v,val;
struct node{
int x;
int val;
node *nxt;
}edge[MAXM*2];
node *head[MAXN],*ncnt=edge;
void add_edge(int x,int y,int val){
ncnt++;
ncnt->nxt=head[x];
ncnt->x=y;
ncnt->val=val;
head[x]=ncnt;
}
queue<int> q;
bool inq[MAXN];
int dist[MAXN],ans;
int vis[MAXN];
int min1(int x,int y){
if(x==-1)
return y;
if(y==-1)
return x;
return min(x,y);
}
void spfa(){
while(!q.empty()){
int y=q.front();
q.pop();
inq[y]=0;
for(node *v=head[y];v!=NULL;v=v->nxt){
int u=v->x;
if(dist[u]>dist[y]+v->val||dist[u]==-1){
dist[u]=dist[y]+v->val;
if(inq[u]==0){
inq[u]=1;
q.push(u);
}
}
}
}
}
int n,m;
int main(){
//freopen("leave.in","r",stdin);
//freopen("leave.out","w",stdout);
int t;
SF("%d",&t);
while(t--){
SF("%d%d",&n,&m);
for(int i=1;i<=n;i++)
head[i]=NULL;
ncnt=edge;
memset(vis,0,sizeof vis);
ans=-1;
for(int i=1;i<=m;i++){
SF("%d%d%d",&u,&v,&val);
add_edge(u,v,val);
add_edge(v,u,val);
}
for(int i=1;i<=n;i<<=1){
memset(dist,-1,sizeof dist);
dist[1]=0;
for(node *v=head[1];v!=NULL;v=v->nxt){
if((v->x)&i){
dist[v->x]=v->val;
q.push(v->x);
}
}
spfa();
for(node *v=head[1];v!=NULL;v=v->nxt)
if(((v->x)&i)==0)
if(dist[v->x]!=-1)
ans=min1(ans,dist[v->x]+v->val);
}
PF("%d\n",ans);
}
}