说下求次小生出树的思路。 先求得最小生成树。
然后枚举不在生成树上的边E(i),将它加入到最小生成树上,则一定会形成一个环,我们把这个环上的最大边删掉,还是一个生成树。得到其权值W(i) 。min(W(i))即是次小生成树
具体实现时这样更简单:求得最小生成树权值min.
求在最小生成树上,任意两点之间的路径上的最大边,并用二维数组maxed[][]记录下来。 (调用多次spfa()实现)。
枚举所有不在生成树上的边,将其加入到最小生成树,并删除掉该环中在最小生成树上的最大边
则可以得到权值为
ans[i] = min+edge[i].w-maxed[u][v]
取ans的最小值即是次小生成树。
#include "iostream"
#include "algorithm"
#include "queue"
using namespace std;
#define MAXSIZE 110
#define INF 999999
int t,m,n;
struct node
{
int u;
int v;
int w;
int flag;
};
node edge[MAXSIZE*MAXSIZE];
queue<int>que;
int f[MAXSIZE];
int e;
int kt;//最小生成树的权值
int vis[MAXSIZE];
int maxed[MAXSIZE][MAXSIZE];
int head[MAXSIZE];
int next[MAXSIZE];
int dis[MAXSIZE];
void addnode(int u,int v,int w,int f)
{
edge[e].u=u;
edge[e].v=v;
edge[e].w=w;
edge[e].flag=f;
next[e]=head[u];
head[u]=e++;
}
bool cmp(node &a,node &b)
{
return a.w<b.w;
}
int findset(int x)
{
if (x==f[x])
return x;
else
return f[x]=findset(f[x]);
}
int kruskal()
{
sort(edge,edge+e,cmp);
int tot=0;
int i;
for (i=1;i<=n;i++)
{
f[i]=i;
}
for (i=0;i<e;i++)
{
if (findset(edge[i].u)!=findset(edge[i].v))
{
//union
f[findset(edge[i].v)]=findset(edge[i].u);
tot+=edge[i].w;
edge[i].flag=1;
}
}
return tot;
}
void spfa(int s)
{
while(!que.empty())
{
que.pop();
}
memset(vis,0,sizeof(vis));
que.push(s);
vis[s]=1;
int i;
for (i=1;i<=n;i++)
{
dis[i]=INF;
}
dis[s]=0;
while(!que.empty())
{
int t=que.front();
que.pop();
for ( i=head[t];i!=-1;i=next[i])
{
if (edge[i].flag&&dis[edge[i].v]>dis[t]+edge[i].w)
{
dis[edge[i].v]=dis[t]+edge[i].w;
if (maxed[s][edge[i].v]<edge[i].w)
{
maxed[edge[i].v][s]=maxed[s][edge[i].v]=edge[i].w;
}
if (!vis[edge[i].v])
{
vis[edge[i].v]=1;
que.push(edge[i].v);
}
}
}
}
}
int judge()
{
int min=INF;
//枚举所有不在生成树上的边
for (int i=0;i<e;i++)
{
if (!edge[i].flag)
{
//ans = min+edge[i].w-maxed[u][v]
int tans=kt+edge[i].w-maxed[edge[i].u][edge[i].v];
if (min>tans)
{
min=tans;
}
}
}
//cout <<min<<endl;
return min==kt;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
e=0;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
memset(maxed,-1,sizeof(maxed));
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addnode(a,b,c,0);
}
//求得最小生成树的权值
kt=kruskal();
// cout<<"kt: "<<kt<<endl;
//bfs 求得点遍历生成树最大的边
for (int i=1;i<=n;i++)
{
maxed[i][i]=0;
spfa(i);
}
//判断是否具有次小生成树
if (judge())
printf("Not Unique!\n");
else
printf("%d\n",kt);
}
return 0;
}