题目描述
给定一张无向图,求图中一个至少包含3个点的环,环上的节点不重复,并且环上的边的长度之和最小。该问题称为无向图的最小环问题。在本题中,你需要输出最小环的方案,若最小环不唯一,输出任意一个均可。若无解,输出No solution.
图的节点数不超过100。
输入描述:
第一行两个正整数n,m表示点数和边数。 接下来m行,每行三个正整数x,y,z,表示节点x,y之间有一条长度为z的边。
输出描述:
输出一个最小环的方案:按环上顺序输出最小环上的点。若最小环不唯一,输出任意一个均可。若无解,输出No solution.
示例1
输入
5 7 1 4 1 1 3 300 3 1 10 1 2 16 2 3 100 2 5 15 5 3 20
输出
1 3 5 2
代码:
#include<bits/stdc++.h>
using namespace std;
const int M=110, N=1e7+10;
int dist[M][M],g[M][M],fa[M][M],path[M];
int n,m,num,mi;
void F()
{
int i,j,k,p,temp;
mi=N;
for(k=1;k<=n;k++)
{
for(i=1;i<k;i++)
for(j=i+1;j<k;j++)
{
temp=dist[i][j]+g[i][k]+g[k][j];
if(temp<mi) //找到更优解
{
mi=temp;
num=0;
p=j;
while(p!=i) //逆向寻找前驱结点直到找到最前面的i,i->…->j
{
path[num++]=p;
p=fa[i][p];//fa[i][j]保存的不是k,而是fa[k][j].
}
path[num++]=i;
path[num++]=k;
}
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
temp=dist[i][k]+dist[k][j];
if(dist[i][j]>temp)
{
dist[i][j]=temp;
fa[i][j]=fa[k][j];
}
}
}
}
int main()
{
int i,j,x,y,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
g[i][j]=N;
dist[i][j]=N;
fa[i][j]=i;
}
while(m--)
{
scanf("%d%d%d",&x,&y,&w);
w=min(g[x][y],w); //处理重边
g[x][y]=g[y][x]=dist[x][y]=dist[y][x]=w;
}
F();
if(mi==N)
printf("No solution.\n");
else
{
printf("%d",path[0]);
for(i=1;i<num;i++)
printf(" %d",path[i]);
printf("\n");
}
}
system("pause");
return 0;
}