poj 1079  判断最…

题意:有n个点 、 给出m条边 , 判断这个图的次小生成树是否唯一?

判断一个次小生成树是否唯一: 首先由kruskal算法求出最小生成树 , 并且记录生成树上 , 任意两点路径上的最大边权 , 然后再把不属于最小生成树的边 , 一条一条加入生成树、再删除该条路径权值最大的边 , 然后再判断新得到的生成树的权值是否和最小生成树的权值一样、

代码:
在代码中 , 我们用数组模拟了链表 , 这个链表是用来存储每一次被生成树加入的点 , 并且不连通的点不属于一个链表 。

#include
#include
#include
#include
using namespace std;

#define maxn 1000000
int  n , m;
int p[110];
int rank[110];
int dist[110][110];

struct node
{
      int u , v;
      int w;
      bool select ;
}grap[10000];

struct xt
{
      int to;
      int next;
}xy[110];

int head[110] , end[110]; //分别表示链表的头指针位置和尾指针位置

bool cmp(node xx , node yy)
{
      return xx.w <= yy.w;
}

void init()
{
      memset(head , -1 , sizeof(head));
      memset(rank , 0 , sizeof(rank));
      for(int i = 1; i <= n; i++)
            p[i] = i;
}

int find(int x)
{
      int g = x , h;
      while(x != p[x])  x = p[x];

      while(p[g] != x)
      {
            h = p[g];
            p[g] = x;
            g = h;
      }
      return x;
}

int inline min(int x ,int y)
{
      if(x < y)  return x;
      return y;
}

int kruskal()
{
      int i , k = 0 , x , y ;
      int sum = 0;
      for(i = 0; i < n; i++)//这里是在用数组模拟链表
      {
            xy[i].to = i+1;
            xy[i].next = head[i+1];
            end[i+1] = i;
            head[i+1] = i;
      }
//初始化时 ,每个点只有自己 , 也就是说 , 每个点都是一颗独立的树
      for(i = 0; i < m; i++)
      {
            x = find(grap[i].u) , y = find(grap[i].v);

            if(x != y)
            {
                  for(int w = head[x] ; w != -1; w = xy[w].next) //把课树上所有的点都存起来,
                        for(int v = head[y] ; v != -1 ; v = xy[v].next)
                              dist[xy[w].to][xy[v].to] = dist[xy[v].to][xy[w].to] = grap[i].w;
//对于这个找每个路径上的最大值 , 为什么不会重复? 因为找的是两个点的路径 , 并且前提条件是这两个点不在同一颗树上(也就是根节点不一样) ,
//而 , 在这次找个之后 , 有把这两树合并成一颗树, 所每个点之间只会碰到一次 ,
                  xy[end[y]].next = head[x];
                  end[y] = end[x];
                  p[x] = y;
                  k++;
                  grap[i].select = true;
                  sum += grap[i].w;
            }
            //else grap[i].select = false;
            if(k >= n-1)  break;
      }
      return sum;
}

int main()
{
      int t;
      cin>>t;
      while(t--)
      {
            scanf("%d %d" , &n , &m);
            init();
            int i ;
            for(i = 0; i < m; i++)
            {
                  scanf("%d %d %d" , &grap[i].u , &grap[i].v , &grap[i].w);
                  grap[i].select = false;
            }

            sort(grap , grap+m , cmp);

            int sum = kruskal();

            int xx = 100000;
            for(i = 0; i < m; i++)
            {
                  if(!grap[i].select)
                  {
                        xx = min(xx , sum + grap[i].w - dist[grap[i].u][grap[i].v]);
                  }
            }
      //      cout<<sum<<","<<xx<<endl;
            if(xx != sum)
                  cout<<sum<<endl;
            else    cout<<"Not Unique!"<<endl;
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值