uva 1265 (LA 4848)

题意:给出一个带权无向图 , 假设存在这样一个子图:子图中至少两个点 , 并且连通 , 子图中的最小边权 ,要比边界边的最大值大(边界边是指 , 一个点在子图中 , 另一个点不在子图中) , 问 ,所有这样子图的顶点数总和是多少?

解法:kruskal的思想,先将边权大的连接,然后判断是否满足  依次连接即可!
我们先考虑用kruskal算法求最大生成树的过程 , 假如我们要加入一条新边 ,如果这条新边上的点和以前已经加入的一些点是可到达的(在这个还未形成的最大生成树上) , 如果这样子图存在 ,那么这个子图肯定包括所有以前加入并且和当前加入点相连(可到达)的点。

代码:

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

#define MAXN 5010
#define INF 0x3f3f3f3f
#define min(x , y)  (x)<(y)?(x):(y)
struct node
{
      int x ,y;
      int w;
}edge[MAXN*2505];

struct node1
{
      int x;
      int w;
}e;


int p[MAXN];
vectorgrap[MAXN];
int n , m , minx , maxx;
int fa;
int num[MAXN];

bool cmp(node x , node y)
{
      return x.w<= y.w;
}

void init()
{
      for(int i =0; i <= n; i++)
      {
            p[i] = i;
            grap[i].clear();
      }

}

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;
      }

      returnx;
}

bool check(int fa)
{
      int i ,j;
      int minx =INF , maxx = 0;
      int x;
      for(i = 1; i<= n; i++)
      {
            x =find(i);
            if(x !=fa)  continue;
            for(j = 0; j< grap[i].size(); j++)
            {
                  x =find(grap[i][j].x);
                  if(x ==fa)
                  {
                        if(grap[i][j].w < minx)  minx =grap[i][j].w;
                  }
                  else  if(grap[i][j].w >maxx)  maxx = grap[i][j].w;
            }
      }

      if(maxx< minx)  return true;
      else returnfalse;
}

int kruskal()
{
      sort(edge ,edge+m , cmp); //对边进行排序

      int i , x ,y , k = 0;

      for(i = 1; i<= n; i++)    p[i]= i;
      for(i = 1; i<= n; i++)    num[i] = 1;
     
      int sum =0;

      for(i = m-1;i >= 0; i--)
      {
            x =find(edge[i].x); // 判断这两个点是不是在同一颗树上
            y =find(edge[i].y);

            if(x !=y)
            {
                  if(k ==(n-2))  break;
                  p[x] =y;
                  num[y] +=num[x];
                 
                  if(check(y))  sum += num[y];
                  k +=1;

            }
      }

      returnsum+n;

     
}

int main()
{
      int t;
      cin>>t;
      while(t--)
      {
            int i;
            scanf("%d%d" , &n , &m) ;
            init();
           
            for(i = 0; i< m; i++)
            {
                  scanf("%d %d%d" , &edge[i].x , &edge[i].y ,&edge[i].w);
                  e.x =edge[i].y , e.w = edge[i].w;
                  grap[edge[i].x].push_back(e);
                  e.x =edge[i].x;
                  grap[edge[i].y].push_back(e);
            }
           
            i =kruskal();
            cout<<i<<endl;
           
           
      }
      return0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值