【图论】【最短路】2018国庆三校联考D1T2

题意:

给出一个无向图,求其中包含点1的最小环。


分析:

这题方法非常的多,(因为结论非常的多)。

比较常见的结论是:最小环一定是最短路树中,不在同一个子树(即从根出发第一个点不同)的两个点之间的边+两点到1的最短距离。

最小环一定是到达某个点的最短+次短路(最短和次短也要求第一个点不同)。

最慢的反而是标算给的方法:对与根相邻的点二进制分组,每次求从一组出发,到达另一组的最短路。

#include
#include
#include
#include
#include
#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);
	}
}

你可能感兴趣的:(图论,最短路)