1. 程式人生 > >POJ1679 Luogu4180 次小生成樹

POJ1679 Luogu4180 次小生成樹

The Unique MST Given a connected undirected graph, tell if its minimum spanning tree is unique.

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V’, E’), with the following properties:

  1. V’ = V.
  2. T is connected and acyclic.

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E’) of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E’. Input The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them. Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string ‘Not Unique!’. Sample Input 2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2 Sample Output 3 Not Unique! 演算法過程: 先求出最小生成樹,然後列舉每一條不再最小生成樹上的邊,並把這條邊放到最小生成樹上面,那麼我們在這條環路上取出一條最長的路,處理新加入的那一條邊,最終得到的權值就是最小生成樹的權值

#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
 
using namespace std;
int n,m;
struct data
{
    int u,v,w;
    bool vis;
} p[20010];
vector<int>G[110];
int per[110],maxd[110][110];
bool cmp(data a,data b)
{
    return a.w < b.w;
}
int Union_Find(int x)
{
    return x == per[x] ? x: per[x] = Union_Find(per[x]);
}
void kruskal()
{
    sort(p,p+m,cmp);
    for(int i=0; i<=n; i++)//初始化
    {
        G[i].clear();
        G[i].push_back(i);
        per[i]=i;
    }
    int sum=0,k=0;//sum是最小生成樹的值
    for(int i=0; i<m; i++)
    {
        if(k==n-1)  break;//n個點,最多n-1條邊
        int x1=Union_Find(p[i].u),x2=Union_Find(p[i].v);
        if(x1!=x2)
        {
            k++;
            p[i].vis=1;//這條邊已經用過了
            sum+=p[i].w;
            int len_x1=G[x1].size();
            int len_x2=G[x2].size();
            for(int j=0; j<len_x1; j++)//更新兩點之間距離的最大值
                for(int k=0; k<len_x2; k++)
                    maxd[G[x1][j]][G[x2][k]]=maxd[G[x2][k]][G[x1][j]]=p[i].w;
            //因為後面的邊會越來越大,所以這裡可以直接等於當前邊的長度
            per[x1]=x2;
            int tem[110];
            for(int j=0; j<len_x2; j++)//現在已經屬於一棵樹了,那麼我們就將點新增到相應的集合中
                tem[j]=G[x2][j];
            for(int j=0; j<len_x1; j++)
                G[x2].push_back(G[x1][j]);
            for(int j=0; j<len_x2; j++)
                G[x1].push_back(tem[j]);
        }
    }
    int cisum=INF;//次小生成樹的權值
    for(int i=0; i<m; i++)
        if(!p[i].vis)
            cisum=min(cisum,sum+p[i].w-maxd[p[i].u][p[i].v]);
    if(cisum>sum)
        printf("%d\n",sum);
    else
        printf("Not Unique!\n");
}
int main()
{
    int T;
    scanf("%d\n",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
            p[i].vis = false;
        }
        kruskal();
    }
    return 0;
}