2018-08-06 并查集&最小生成树

  • A  -- The Suspects

  • Description

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).
Once a member in a group is a suspect, all members in the group are suspects.
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects

  • Input

The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n ≤ 30000 and 0 ≤ m ≤ 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space. A case with n = 0 and m = 0 indicates the end of the input, and need not be processed

  • Output

For each case, output the number of suspects in one line

  • Sample Input

100 4

2 1 2

5 10 13 11 12 14

2 0 1

2 99 2

200 2

1 5

5 1 2 3 4 5

1 0

0 0
 

  • Sample Output

4

1

1

  • 题目理解

查询的过程中进行路径压缩,使用cnt数组计数,在两棵树根节点合并的时候将树上的元素个数更新,记住一定要判断f1!=f2时才转移father(f1)=f2否则计数会产生错误不说,而且可能产生环导致后面的程序错误或者崩溃

#include<cstdio>
const int maxn=30005;
int father[maxn],cnt[maxn];
int find_father(int x){
    int f=x;
    while(father[f]!=f)f=father[f];
    while(father[x]!=x){
        int son=x;
        x=father[x];//记录下原来的father
        father[son]=f;
        //printf("!!!!%d  %d\n",son,father[son]);
    }
    return f;
}
int main(){
    int n,m,k,x,y;
    while(~scanf("%d%d",&n,&m)&&n){
        for(int i=0;i<n;++i){
            father[i]=i;
            cnt[i]=1;
        }
        while(m--){
            scanf("%d%d",&k,&x);
            int f1=find_father(x);
            for(int i=0;i<k-1;++i){
                scanf("%d",&y);
                int f2=find_father(y);
                if(f1!=f2){
                 father[f2]=f1;
                 cnt[f1]+=cnt[f2];
                }
            }
        }
        printf("%d\n",cnt[find_father(0)]);
    }
    return 0;
}

 

  • B  -- A Bug's Life

  • Description

Background
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs
Problem
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it

  • Input

The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one

  • Output

The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong

  • Sample Input

2

3 3

1 2

2 3

1 3

4 2

1 2

3 4

  • Sample Output

Scenario #1:

Suspicious bugs found!

 

Scenario #2:

No suspicious bugs found!

 

  • 题目理解

由于这道题有两类生物,如果两个生物出现作为同一个生物的异性,那么前面两个生物的集合应该合并成为一个集合,这时候再开一个数组记录当前出现过的生物的异性,在以后出现这个生物时如果其异性有记录就将当前异性所在的集合合并,但是判断只需要查看两种异性生物对在不在同一棵数内即可。

#include<cstdio>
#include<cstring>
const int maxn=2005;
int father[maxn],pst[maxn];
int find_father(int x){
   return x==father[x]?x:father[x]=(find_father(father[x]));
}
int main()
{
    int t,n,m,a,b;
    scanf("%d",&t);
    for(int i=1;i<=t;++i){
        bool flag=false;
        scanf("%d%d",&n,&m);
        for(int j=0;j<=n;++j)
            father[j]=j;
        memset(pst,-1,sizeof(int)*(n+1));
        while(m--){
            scanf("%d%d",&a,&b);
            if(flag) continue;
            int fa=find_father(a);
            int fb=find_father(b);
            //printf("!!!%d %d %d %d\n",i,m,fa,fb);
            if(fa==fb){
                flag=true;
                continue;
            }
            if(pst[a]!=-1){
                int f_oa=find_father(pst[a]);
                if(fb!=f_oa)
                    father[fb]=f_oa;
            }else pst[a]=b;
            if(pst[b]!=-1){
                int f_ob=find_father(pst[b]);
                if(fb!=f_ob)
                    father[fa]=f_ob;
            }else pst[b]=a;
        }
        printf("Scenario #%d:\n",i);
        if(flag)
            printf("Suspicious bugs found!\n\n");
        else
            printf("No suspicious bugs found!\n\n");
    }
    return 0;
}

 

  • C  -- 食物链

  • Description

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类
第二种说法是"2 X Y",表示X吃Y
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数

  • Input

第一行是两个整数N和K,以一个空格分隔
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类
若D=1,则表示X和Y是同类
若D=2,则表示X吃Y

  • Output

只有一个整数,表示假话的数目

  • Sample Input

100 7

1 101 1

2 1 2

2 2 3

2 3 3

1 1 3

2 3 1

1 5 5

  • Sample Output

3

  • 题目理解

刚开始想同第二题的做法来判断出现的数字的关系,但是有可能出现不在一棵树但是不知道到底是吃还是被吃的关系,这就很尴尬了,因为这个判断不再为二元。那么我们还需要在通过一个标记记录所有结点的关系,因为结点十分地多我们可以通过相对值(相对于根节点的值判断当前的关系)看出现新的关系的时候是否出现矛盾,就可以看出是否是谎言。r(x)=0/1/2表示x与根同类、x被根吃、x吃根。在路径压缩改变father(i)的值的通式需要改变r(i)的值,当我们有r(a_1)_{f}(表示a_1相对于根节点f的关系)和r(a_2)_{a_1}可以通过对所有情况推导得出r(a_2)_f=(r(a_1)_f+r(a_2)_{a_1})%3;其余都可以通过相对关系推出是否相矛盾,以及添加新的关系时的处理。

#include<cstdio>
const int maxn=50001;
int father[maxn],r[maxn],n;
int findset(int x)
{
	if(father[x]!=x)
	{
		int fx=findset(father[x]);
		r[x]=(r[x]+r[father[x]])%3;
		father[x]=fx;
	}
	return father[x];
}

bool Union(int d,int x,int y)
{
	int fx=findset(x),fy=findset(y);
	if(fx==fy)
	{
		if((r[y]-r[x]+3)%3!=d-1)return 1;
		else return 0;
	}
	father[fy]=fx;//前面的语句不能对现在的关系造成影响
	r[fy]=(r[x]-r[y]+d-1+3)%3;
	return 0;
}
int main()
{
	int k,ans,d,x,y;
	scanf("%d%d",&n,&k);
	ans=0;
	for(int i=1;i<=n;i++)father[i]=i,r[i]=0;
	while(k--)
	{
		scanf("%d%d%d",&d,&x,&y);
		if(x>n||y>n||(x==y&&d==2)){ans++;continue;}
		if(Union(d,x,y))ans++;
	}
	printf("%d\n",ans);
	return 0;
}

 

  • D  -- X-Plosives

  • Description

A secret service developed a new kind of explosive that attain its volatile property only when a specific association of products occurs. Each product is a mix of two different simple compounds, to which we call a binding pair. If N > 2, then mixing N different binding pairs containing N simple compounds creates a powerful explosive. For example, the binding pairs A+B, B+C, A+C (three pairs, three compounds) result in an explosive, while A+B, B+C, A+D (three pairs, four compounds) does not. You are not a secret agent but only a guy in a delivery agency with one dangerous problem: receive binding pairs in sequential order and place them in a cargo ship. However, you must avoid placing in the same room an explosive association. So, after placing a set of pairs, if you receive one pair that might produce an explosion with some of the pairs already in stock, you must refuse it, otherwise, you must accept it. An example. Lets assume you receive the following sequence: A+B, G+B, D+F, A+E, E+G, F+H. You would accept the first four pairs but then refuse E+G since it would be possible to make the following explosive with the previous pairs: A+B, G+B, A+E, E+G (4 pairs with 4 simple compounds). Finally, you would accept the last pair, F+H. Compute the number of refusals given a sequence of binding pairs

  • Input

The input will contain several test cases, each of them as described below. Consecutive test cases are separated by a single blank line. Instead of letters we will use integers to represent compounds. The input contains several lines. Each line (except the last) consists of two integers (each integer lies between 0 and 105) separated by a single space, representing a binding pair. Each test case ends in a line with the number ‘-1’. You may assume that no repeated binding pairs appears in the input

  • Output

For each test case, the output must follow the description below. A single line with the number of refusals

  • Sample Input

1 2

3 4

3 5

3 1

2 3

4 1

2 6

6 5

-1

  • Sample Output

3

  • 题目理解

算是最标准的并查集题目了,如果成环其实也就是两个点已经出现在一棵树上,如果添加当前边就一定会成环,以为一棵树上的两个点一定是可达的随意连接任意两点就会出现环,所以每次添加边判断是否出现在同一棵数上即可,如果同就拒绝

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=100005;
int father[maxn];
int find_father(int x)
{
	return x==father[x]?x:father[x]=find_father(father[x]);

}
int main()

{

	for(int i=0;i<maxn;i++)
		father[i] = i;
	int ans=0;
	int a,b;
	while(scanf("%d",&a)!=EOF)
	{
		if(a == -1)
		{
			printf("%d\n",ans);
			ans = 0;
			for(int i=0;i<maxn;i++)
		        father[i] = i;
			continue;
		}
		else scanf("%d",&b);
		int fa=find_father(a);
		int fb=find_father(b);
		if(fa==fb)
			ans++;
		else father[fa]=fb;
	}
	return 0;
}

 

  • G  -- Networking

  • Description

You are assigned to design network connections between certain points in a wide area. You are given a set of points in the area, and a set of possible routes for the cables that may connect pairs of points. For each possible route between two points, you are given the length of the cable that is needed to connect the points over that route. Note that there may exist many possible routes between two given points. It is assumed that the given possible routes connect (directly or indirectly) each two points in the area. Your task is to design the network for the area, so that there is a connection (direct or indirect) between every two points (i.e., all the points are interconnected, but not necessarily by a direct cable), and that the total length of the used cable is minimal

  • Input

The input file consists of a number of data sets. Each data set defines one required network. The first line of the set contains two integers: the first defines the number P of the given points, and the second thenumber R ofgivenroutesbetweenthepoints. Thefollowing R linesdefinethegivenroutesbetween the points, each giving three integer numbers: the first two numbers identify the points, and the third gives the length of the route. The numbers are separated with white spaces. A data set giving only one number P = 0 denotes the end of the input. The data sets are separated with an empty line. The maximal number of points is 50. The maximal length of a given route is 100. The number of possible routes is unlimited. The nodes are identified with integers between 1 and P (inclusive). The routes between two points i and j may be given as ‘i j’ or as ‘j i’

  • Output

For each data set, print one number on a separate line that gives the total length of the cable used for the entire designed network

  • Sample Input

1 0
2 3

1 2 37

2 1 17

1 2 68
3 7

1 2 19

2 3 11

3 1 7

1 3 5

2 3 89

3 1 91

1 2 32
5 7

1 2 5

2 3 7

2 4 8

4 5 11

3 5 10

1 5 6

4 2 12
0

  • Sample Output

0

17

16

26

  • 题目理解

最小生成树的总长度(倾向使用Kruskal),优先队列维护最小边,只需要判断当前边的两个点是否在一棵树上就可以判断是否成环舍去了,理由和D题一样

#include<cstdio>
#include<queue>
using namespace std;
struct ver{
  int u,v,w;
  ver(int U,int V,int W):u(U),v(V),w(W){}
  friend bool operator<(const ver& a,const ver& b){
     return a.w>b.w;
  }
};
const int maxn=55;
int father[maxn];
int find_father(int x){
    return x==father[x]?x:father[x]=find_father(father[x]);
    //查找并且路径压缩
}
int main()
{
    int n,m;
    int u,v,w;
    while(~scanf("%d",&n)&&n){
        scanf("%d",&m);
        priority_queue<ver> p;
        for(int i=0;i<maxn;++i)
            father[i]=i;
        while(m--){
            scanf("%d%d%d",&u,&v,&w);
            p.push(ver(u,v,w));
        }
        int sum=0,cnt=0;
        ver cur=ver(0,0,0);
        while(!p.empty()){
            cur=p.top();
            p.pop();
            u=cur.u;
            v=cur.v;
            int fu=find_father(u);
            int fv=find_father(v);
            if(fu==fv) continue;
            sum+=cur.w;
            father[fu]=fv;
            if((++cnt)==n-1) break;
        }
        printf("%d\n",sum);
    }
    return 0;
}

 

  • H  -- Arctic Network

  • Description

The Department of National Defence(DND)wishestoconnectseveral northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will inadditionhaveasatellitechannel. Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if thedistancebetweenthemdoesnot exceed D, which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts. Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (directorindirect)betweeneverypair of outposts.

  • Input

The first line of input contains N, the number of test cases. The first line of each test case contains 1 ≤ S ≤ 100, the number of satellite channels, and S < P ≤ 500, the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000)

  • Output

For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal point

  • Sample Input

1

2 4

0 100

0 300

0 600

150 750 

  • Sample Output

212.13

  • 题目理解

因为有s个卫星频道所以我们可以这样理解。当我们得到最小生成树的时候可以为其中s个点分配卫星,而分配的时候带来的结果相当于s-1条边的花费为0,这时候将剩下的边找出来,而第((m-1)-(s-1))条边是所求的最大花费就是花费的最小值,因为边是按照升序选择的

#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
struct ver{
  int u,v;
  double w;
  ver(int U,int V,double W):u(U),v(V),w(W){}
  friend bool operator<(const ver& a,const ver& b){
     return a.w>b.w;
  }
};
const int maxn=505;
int father[maxn];
double x[maxn],y[maxn];
int find_father(int x){
    return x==father[x]?x:father[x]=find_father(father[x]);
}
int main()
{
    int n,s,m;
    int u,v;
    double w;
    while(~scanf("%d",&n)){
       while(n--){
          scanf("%d%d",&s,&m);
          priority_queue<ver> p;
          for(int i=0;i<maxn;++i)
             father[i]=i;
          for(int i=1;i<=m;++i){
            scanf("%lf%lf",&x[i],&y[i]);
            for(int j=i-1;j>=1;--j){
                w=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
                //printf("!!!%lf\n",w);
                p.push(ver(i,j,w));
            }
          }
          double ans=0;
          int cnt=0;
          ver cur=ver(0,0,0);
          while(!p.empty()){
            cur=p.top();
            p.pop();
            u=cur.u;
            v=cur.v;
            //printf("!!%lf\n",cur.w);
            int fu=find_father(u);
            int fv=find_father(v);
            if(fu==fv) continue;
            ans=cur.w;
            father[fu]=fv;
            if((++cnt)==m-s) break;
          }
          printf("%.2lf\n",ans);
       }
    }
    return 0;
}

 

  • J  -- Frogger

  • Description

Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists’ sunscreen, he wants to avoid swimming and instead reach her by jumping. UnfortunatelyFiona’sstoneisoutofhisjumprange. ThereforeFreddyconsiderstouseotherstones as intermediate stops and reach her by a sequence of several small jumps. To execute a given sequence of jumps, a frog’s jump range obviously must be at least as long as the longest jump occuring in the sequence. The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones. Youaregiventhecoordinates ofFreddy’sstone, Fiona’sstone andall otherstones inthe lake. Your job is to compute the frog distance between Freddy’s and Fiona’s stone

  • Input

The input file will contain one or more test cases. The first line of each test case will contain the number of stones n (2 ≤ n ≤ 200). The next n lines each contain two integers xi, yi (0 ≤ xi,yi ≤ 1000) representing the coordinates of stone #i. Stone #1 is Freddy’s stone, stone #2 is Fiona’s stone, the other n−2 stones are unoccupied. There’s a blank line following each test case. Input is terminated by a value of zero (0) for n

  • Output

For each test case, print a line saying ‘Scenario #x’ and a line saying ‘Frog Distance = y’ where x is replaced by the test case number (they are numbered from 1) and y is replaced by the appropriate real number, printed to three decimals. Put a blank line after each test case, even after the last one

  • Sample Input

2

0 0

3 4
3

17 4

19 4

18 5

  • Sample Output

Scenario #1

Frog Distance = 5.000


Scenario #2

Frog Distance = 1.414

 

  • 题目理解

这道题和上一题思路有相似之处,在构建最小生成树的时候筛选边的时候找到最大值就可以了,但是记住当1和2号结点在一棵树上的时候就要退出循环了因为已经可达了 后面的更大的边都没有意义了

#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
struct ver{
  int u,v;
  double w;
  ver(int U,int V,double W):u(U),v(V),w(W){}
  friend bool operator<(const ver& a,const ver& b){
     return a.w>b.w;
  }
};
const int maxn=205;
int father[maxn];
double x[maxn],y[maxn];
int find_father(int x){
    return x==father[x]?x:father[x]=find_father(father[x]);
}
int main()
{
    int n,u,v,cas=0;
    double w;
    while(~scanf("%d",&n)&&n){
          priority_queue<ver> p;
          for(int i=0;i<maxn;++i)
             father[i]=i;
          for(int i=1;i<=n;++i){
            scanf("%lf%lf",&x[i],&y[i]);
            for(int j=i-1;j>=1;--j){
                w=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
                //printf("!!!%lf\n",w);
                p.push(ver(i,j,w));
            }
          }
          double ans=-1;
          int cnt=0;
          ver cur=ver(0,0,0);
          while(!p.empty()){
            cur=p.top();
            p.pop();
            u=cur.u;
            v=cur.v;
            //printf("!!%lf\n",cur.w);
            int fu=find_father(u);
            int fv=find_father(v);
            if(fu==fv) continue;
            ans=max(ans,cur.w);
            father[fu]=fv;
            if((++cnt)==n-1) break;
            if(find_father(1)==find_father(2))break;
          }
          printf("Scenario #%d\n",++cas);
          printf("Frog Distance = %.3lf\n\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值