ACM-最小生成树之Count the Pairs——hdu4750

Count The Pairs

Problem Description
ACM-最小生成树之Count the Pairs——hdu4750_第1张图片
  With the 60th anniversary celebration of Nanjing University of Science and Technology coming soon, the university sets n tourist spots to welcome guests. Of course, Redwood forests in our university and its Orychophragmus violaceus must be recommended as top ten tourist spots, probably the best of all. Some undirected roads are made to connect pairs of tourist spots. For example, from Redwood forests (suppose it’s a) to fountain plaza (suppose it’s b), there may exist an undirected road with its length c. By the way, there is m roads totally here. Accidently, these roads’ length is an integer, and all of them are different. Some of these spots can reach directly or indirectly to some other spots. For guests, they are travelling from tourist spot s to tourist spot t, they can achieve some value f. According to the statistics calculated and recorded by us in last years, We found a strange way to calculate the value f:
  From s to t, there may exist lots of different paths, guests will try every one of them. One particular path is consisted of some undirected roads. When they are travelling in this path, they will try to remember the value of longest road in this path. In the end, guests will remember too many longest roads’ value, so he cannot catch them all. But, one thing which guests will keep it in mind is that the minimal number of all these longest values. And value f is exactly the same with the minimal number.
  Tom200 will recommend pairs (s, t) (start spot, end spot points pair) to guests. P guests will come to visit our university, and every one of them has a requirement for value f, satisfying f>=t. Tom200 needs your help. For each requirement, how many pairs (s, t) you can offer?
 

Input
  Multiple cases, end with EOF.
  First line:n m
  n tourist spots ( 1<n<=10000), spots’ index starts from 0.
  m undirected roads ( 1<m<=500000).

  Next m lines, 3 integers, a b c
  From tourist spot a to tourist spot b, its length is c. 0<a, b<n, c(0<c<1000000000), all c are different.

  Next one line, 1 integer, p (0<p<=100000)
  It means p guests coming.

  Next p line, each line one integer, t(0<=t)
  The value t you need to consider to satisfy f>=t.
 

Output
  For each guest's requirement value t, output the number of pairs satisfying f>=t.
  Notice, (1,2), (2,1) are different pairs.
 

Sample Input
   
   
   
   
2 1 0 1 2 3 1 2 3 3 3 0 1 2 0 2 4 1 2 5 5 0 2 3 4 5
 

Sample Output
   
   
   
   
2 2 0 6 6 4 4 0 这是一道2013年南京赛区网络赛的一道题目,题意大致为: 南京大学60周年校庆来临,有许多景点,每个景点间有多条道路连接,每条道路有相应的观赏值,游客来到南京大学游玩 有观赏值的需求,需要求出有多少对景点能满足游客观赏值,注意:1到2和2到1是两对景点。 观赏值的计算方法为:先求出两点间一条道路的观赏值,由于游客,记忆力有限,当从一个点到另一个景点要经过多段道 路时,游客只会记得最大的观赏值,也就是说,一条道路的观赏值为 此条路各段小路取最大。再因为一个景点到另一个景点不 可能只有一条道路,所以,要将各条道路的比较,取最大为此两点间的观赏值。 总结下来就是:先求一条路的观赏值->再求两个点之间的观赏值 算法: 这些点最终连接起来,肯定成为一个最小生成树,于是,用最小生成树合并边的方法来计算。再者,因为求符合要求的可能 性太多,所以我们可以先算不符合要求的,再用总的减去不符合要求的,即为答案。此处用kruskal算法生成最小生成树。 代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>							// sort函数头文件

using namespace std;

// 建立结构体,存点到点之间的权值
struct node
{
    int u,v,len;
    bool operator <(const node &a)const{		// 重载运算符<
        return len<a.len;
    }
}nd[500005];

// 建立结构体,存储各个游客的观赏值,id用来存储序号
struct tourist
{
    int gs,id;
    bool operator <(const tourist &a)const{		// 重载运算符<
        return gs<a.gs;
    }
}t[500005];

// num记录此点连接点的个数,fa记录寻根节点,tourt记录游客观赏值
int num[500005],fa[500005],tourt[500005];

// 并查集,用来判断是否构成环路等
int find(int x)
{
    if(x!=fa[x])
        fa[x]=find(fa[x]);
    return fa[x];
}


int main()
{
    int n,m,j,i,p;
    while(scanf("%d%d",&n,&m)!=EOF)			
    {
		// 输入点相关数据
        for(i=0;i<m;i++)
            scanf("%d%d%d",&nd[i].u,&nd[i].v,&nd[i].len);
        // 输入游客相关数据
		scanf("%d",&p);
        for(i=0;i<p;i++)
        {
            scanf("%d",&t[i].gs);
            t[i].id=i;
        }
		
		// 对 权值排序,对游客观赏值需求排序
        sort(nd,nd+m);
        sort(t,t+p);
        
		// 对num,fa数组初始化
		for(i=0;i<n;i++)
        {
            fa[i]=i;
            num[i]=1;
        }

        int total=n*(n-1);
        int sum=0;
        j=0;
        
		for(i=0;i<p;i++)
        {
            while(j<m&&nd[j].len<t[i].gs)
            {	
				// f1,f2均为寻找根节点
                int f1=find(nd[j].u);
                int f2=find(nd[j].v);

                if(f1==f2)
                {
                    j++;
                    continue;
                }
				// sum改变,根节点更新,点连接更新
                sum+=num[f1]*num[f2]*2;
                fa[f1]=f2;
                num[f2]+=num[f1];
                j++;
            }

			// 总数减去不符合要求的即为所求的
            tourt[t[i].id]=total-sum;
        }

		//输出 符合 游客观赏值的点对数
        for(i=0;i<p;i++)
            printf("%d\n",tourt[i]);
    }
    return 0;
}



最后还要注意一点,由于数据很大,用scanf,printf,不要用cin,cout。

你可能感兴趣的:(最小生成树,ACM,count,the,pairs,hdu4750)