【POJ1679】The Unique MST

  1 //ver1: Kruskal+暴力枚举删除边
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<algorithm>
  5 using namespace std;
  6 int t,n,m,first;
  7 int a,ok,minx,p[101];
  8 struct edge{
  9     int v1,v2,d,v;  //v标记MST中的每一条边
 10 }e[10001];
 11 int findp(int x){
 12     return x==p[x]?x:p[x]=findp(p[x]);
 13 }
 14 int cmp(edge a,edge b){
 15     return a.d<b.d;
 16 }
 17 void init(){
 18     cin>>n>>m;
 19     ok=1;first=1;
 20     for(int i=0;i<m;i++){
 21         cin>>e[i].v1>>e[i].v2>>e[i].d;
 22         e[i].v=0;
 23     }
 24     sort(e,e+m,cmp);
 25 }
 26 int Kruskal(){
 27     for(int i=1;i<=n;i++)
 28         p[i]=i;
 29     a=n; int sum=0;
 30     for(int i=0;i<m;i++){
 31         int p1=findp(e[i].v1),p2=findp(e[i].v2);
 32         if(p1!=p2){
 33             sum+=e[i].d;
 34             a--;
 35             p[p1]=p2;
 36             if(first) e[i].v=1;  //边i属于MST
 37         }
 38         if(a==1) break;
 39     }
 40     if(a==1) return sum;
 41     return -1;
 42 }
 43 int main(){
 44     cin>>t;
 45     while(t--){
 46         init();
 47         minx=Kruskal();        //求MST
 48         first=0;               //注意MST已经求过了
 49         for(int i=0;i<m;i++){
 50             if(e[i].v){        //删除MST中的一条边,再添加一条边形成连通图
 51                 int t=e[i].v1; //把这条件的两个点变成一个点,从而在下面的Kruskal中不会再选择这条边
 52                 e[i].v1=e[i].v2;
 53                 int sum=Kruskal();
 54                 if(sum==minx) {ok=0;break;}
 55                 e[i].v1=t;
 56             }
 57         }
 58         if(ok) cout<<minx<<endl;
 59         else cout<<"Not Unique!\n";
 60     }
 61 }
 62 //ver2:Kruskal+判断是否存在权值相等且连接的等价集合相同
 63 #include<cstdio>
 64 #include<iostream>
 65 #include<algorithm>
 66 using namespace std;
 67 int t,n,m,a,minx,ok,p[101];
 68 struct edge{
 69     int x,y,w;
 70 }e[10001];
 71 int cmp(edge a,edge b){
 72     return a.w<b.w;
 73 }
 74 int findp(int x){
 75     return x==p[x]?x:p[x]=findp(p[x]);
 76 }
 77 void init(){
 78     minx=0;ok=1;
 79     scanf("%d%d",&n,&m); a=n;
 80     for(int i=1;i<=n;i++) p[i]=i;
 81     for(int i=0;i<m;i++)
 82         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
 83     sort(e,e+m,cmp);
 84 }
 85 void Kruskal(){
 86     for(int i=0;i<m;i++){
 87         int p1=findp(e[i].x),p2=findp(e[i].y);
 88         if(p1!=p2){
 89             for(int j=i+1;j<m;j++)
 90                 if(e[i].w==e[j].w){
 91                     //判断链接的是否是相同的集合
 92                     int p3=findp(e[j].x),p4=findp(e[j].y);
 93                     if(p3==p1&&p4==p2||p3==p2&&p4==p1){
 94                         ok=0;
 95                         return;
 96                     }
 97                 }
 98                 else break;//由于e[]是有序的,发现权值不同,立即退出循环
 99             p[p1]=p2;
100             minx+=e[i].w;
101             a--;
102         }
103         if(a==1) break;
104     }
105 }
106 int main()
107 {
108     scanf("%d",&t);
109     while(t--){
110         init();
111         Kruskal();
112         if(ok) printf("%d\n",minx);
113         else printf("Not Unique!\n");
114     }
115 }
116 //ver3: 可以前后求两次MST,在权值相同的情况下,第一次边编号小的优先选,第二次边编号大的优先选,
117 //判断两次MST是否相同即可(一是最短路径和是否相等,二是所有的边是否相同) 

判断最小生成树是否唯一

时间: 2024-10-12 17:59:58

【POJ1679】The Unique MST的相关文章

【KM】BZOJ1937 [Shoi2004]Mst 最小生成树

这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. [思路] 思路有点神,并不是我这种蒟蒻能够想到的XD 显然由贪心,树边必定变成wi-di,非树边必定变成wi+di (di≥0) 为了满足Mst的性质,考察一条非树边j,它加最小生成树后,必定构成一个环.对于环上的每一条树边i,有wi-di≤wj+dj,即di+dj≥wi-wj.这非常类似于KM的

【POJ 1679 The Unique MST】最小生成树

无向连通图(无重边),判断最小生成树是否唯一,若唯一求边权和. 分析生成树的生成过程,只有一个圈内出现权值相同的边才会出现权值和相等但“异构”的生成树.(并不一定是最小生成树) 分析贪心策略求最小生成树的过程(贪心地选最短的边来扩充已加入生成树的顶点集合U),发现只有当出现“U中两个不同的点到V-U中同一点的距离同时为当前最短边”时,才会出现“异构”的最小生成树. 上图为kruscal和prim生成过程中可能遇到的相等边的情况,红色和蓝色的为权值相等的边. 可以看到kruscal由于事先将所有边

【POJ 1679】The Unique MST(次小生成树)

找出最小生成树,同时用Max[i][j]记录i到j的唯一路径上最大边权.然后用不在最小生成树里的边i-j来替换,看看是否差值为0. #include <algorithm> #include <cstdio> #include <cstring> using namespace std; const int N=101; const int INF=0x3f3f3f3f; int n,m,ans,s; int lowc[N],vis[N],g[N][N]; int Ma

「POJ1679 」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 prope

【LeetCode】063. Unique Paths II

题目: Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid. For example, There is one obstacle in the m

【LeetCode】96 - Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For example,Given n = 3, there are a total of 5 unique BST's. 1 3 3 2 1 \ / / / \ 3 2 1 1 3 2 / / \ 2 1 2 3 Tree Dynamic Programming Solution 1:  递归 1 class So

【leetcode】1207. Unique Number of Occurrences

题目如下: Given an array of integers arr, write a function that returns true if and only if the number of occurrences of each value in the array is unique. Example 1: Input: arr = [1,2,2,1,1,3] Output: true Explanation: The value 1 has 3 occurrences, 2 h

【LeetCode】96. Unique Binary Search Trees-唯一二叉排序树的个数

一.描述: 二.思路: BST(二叉排序树):中序遍历的结果为非递减序列,并且节点(个数和值)相同的不同二叉树的中序遍历结果都相同: 当左子树的节点个数确定后,右子树的个数也随之确定: 当节点个数为0或1时,二叉树只有1种,表示为f(0)=1,f(1)=f(0)*f(0): 当节点个数为2时,总的种类数=左子树为空f(0)*右子树不为空f(1)+左子树不为空f(1)*右子树为空f(0),即f(0)*f(1)+f(1)*f(0)=2种: 当节点个数为3时,有左子树为空f(0)*右子树不为空f(2)

【leetcode】23.Unique Binary Search Trees

以i为根节点时,其左子树构成为[0,...,i-1],其右子树构成为[i+1,...,n]构成.根结点确定时,左子树与右子树的结点个数都是确定的. 这样就可以把这个问题化成子问题.因此可以用动态规划解. Sigma(左边的子树可能状态 * 右边子树可能状态) = 当前个数的结点可能的状态数. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Solution {     public int numTrees(int n