并查集的介绍可以看下https://www.cnblogs.com/jkzr/p/10290488.html
A - Wireless Network POJ - 2236
In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations.
Input
1. "O p" (1 <= p <= N), which means repairing computer p.
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate.
The input will not exceed 300000 lines.
Output
Sample Input
4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4
Sample Output
FAIL
SUCCESS 题意:给你N台电脑,编号从1到N。一个数字,表示两台计算机的最大通信距离,超过这个距离就无法进行通信。然后分别告诉这些电脑的坐标。
接下来有两种操作,第一种O表示这点电脑修好,第二种S,表示测试这两台电脑能不能进行正常的通信。
思路:并查集的简单应用,对每次修好的电脑对其它已经修好的电脑遍历,如果距离小于等于最大通信距离就将他们合并。之后判断2台电脑是不是一个集合中就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,d;
int fa[maxn];
bool vis[maxn];
struct Node
{
int x,y;
}node[maxn];
void init()
{
for(int i=;i<=n;i++)
fa[i]=i;
memset(vis,false,sizeof(vis));
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
fa[fx]=fy;
}
int getdist(int a,int b)
{
return (node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y);
}
int main()
{
scanf("%d %d",&n,&d);
init();
for(int i=;i<=n;i++)
scanf("%d %d",&node[i].x,&node[i].y);
char c;int p,q;
while(cin>>c)
{
if(c=='O')
{
scanf("%d",&p);
vis[p]=true;
for(int i=;i<=n;i++)
{
if(vis[i]&&i!=p)
{
if(getdist(i,p)<=d*d)
join(i,p);
}
}
}
else
{
scanf("%d %d",&p,&q);
if(findd(p)==findd(q))
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
return ;
}
B - The Suspects POJ - 1611
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
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.
Output
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
题意:有很多组学生,在同一个组的学生经常会接触,也会有新的同学的加入。但是SARS是很容易传染的,只要在改组有一位同学感染SARS,那么该组的所有同学都被认为得了SARS。
计算出有多少位学生感染SARS了。假定编号为0的同学是得了SARS的。
思路:我们把在一个组的学生合并到同一个集合里面。用一个cnt[]数组记录每一个以当前下标为根节点的集合的个体数目,最后输出0号的根节点对应的cnt值,就是0号学生所在团体的人数,也就是我么要求的答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,m;
int fa[maxn];
int cnt[maxn];
void init()
{
for(int i=;i<=n;i++)
{
fa[i]=i;
cnt[i]=;
}
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
{
fa[fx]=fy;
cnt[fy]+=cnt[fx];
}
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==&&m==)
break;
init();
while(m--)
{
int num,a,b;
scanf("%d",&num);
scanf("%d",&a);
for(int i=;i<num;i++)
{
scanf("%d",&b);
join(a,b);
}
}
printf("%d\n",cnt[findd()]);
}
return ;
}
C - How Many Tables HDU - 1213
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
InputThe input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
OutputFor each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
Sample Input
2
5 3
1 2
2 3
4 5 5 1
2 5
Sample Output
2
4 题意:Ignatius的生日,他邀请了许多朋友。现在是吃晚饭的时间,Ignatius想知道他至少需要准备多少桌。必须注意的是,并非所有的朋友都相互认识对方,有的人不愿意和陌生人坐在一桌。
针对此问题的一个重要的规则是,如果我告诉你A知道B,B知道C,这意味着,A和C认识对方,这样他们就可以留在一个桌子。
但是如果我告诉你,A知道B,B知道C,D知道E,那么ABC可以坐在一起,DE就得另外再坐一桌了。你的任务是请根据输入的朋友之间的关系,帮助Ignatius 求出需要安排多少桌。
思路:我们还是一样用开一个cnt[]数组,初始值为1,代表一个人一个桌子。后面添加认识的条件的时候如果两个人认识的话我们就合并,并把儿子的cnt值职位0,这样的话到最后统计所有的cnt的值就知道要准备多少桌子了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int T,n,m,ans;
int fa[maxn];
int cnt[maxn];
void init()
{
for(int i=;i<=n;i++)
{
fa[i]=i;
cnt[i]=;
}
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
{
fa[fx]=fy;
cnt[fx]=;
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
init();
while(m--)
{
int a,b;
scanf("%d %d",&a,&b);
join(a,b);
}
ans=;
for(int i=;i<=n;i++)
ans+=cnt[i];
printf("%d\n",ans);
}
return ;
}
D - How Many Answers Are Wrong HDU - 3038
FF is a bad boy, he is always wooing TT to play the following game with him. This is a very humdrum game. To begin with, TT should write down a sequence of integers-_-!!(bored).
Then, FF can choose a continuous subsequence from it(for example the subsequence from the third to the fifth integer inclusively). After that, FF will ask TT what the sum of the subsequence he chose is. The next, TT will answer FF's question. Then, FF can redo this process. In the end, FF must work out the entire sequence of integers.
Boring~~Boring~~a very very boring game!!! TT doesn't want to play with FF at all. To punish FF, she often tells FF the wrong answers on purpose.
The bad boy is not a fool man. FF detects some answers are incompatible. Of course, these contradictions make it difficult to calculate the sequence.
However, TT is a nice and lovely girl. She doesn't have the heart to be hard on FF. To save time, she guarantees that the answers are all right if there is no logical mistakes indeed.
What's more, if FF finds an answer to be wrong, he will ignore it when judging next answers.
But there will be so many questions that poor FF can't make sure whether the current answer is right or wrong in a moment. So he decides to write a program to help him with this matter. The program will receive a series of questions from FF together with the answers FF has received from TT. The aim of this program is to find how many answers are wrong. Only by ignoring the wrong answers can FF work out the entire sequence of integers. Poor FF has no time to do this job. And now he is asking for your help~(Why asking trouble for himself~~Bad boy)
InputLine 1: Two integers, N and M (1 <= N <= 200000, 1 <= M <= 40000). Means TT wrote N integers and FF asked her M questions.
Line 2..M+1: Line i+1 contains three integer: Ai, Bi and Si. Means TT answered FF that the sum from Ai to Bi is Si. It's guaranteed that 0 < Ai <= Bi <= N.
You can assume that any sum of subsequence is fit in 32-bit integer.
OutputA single line with a integer denotes how many answers are wrong.Sample Input
10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
Sample Output
1
题意:给出区间[1,n],下面有m组数据,l r v代表区间[l,r]之和为v,每输入一组数据,判断此组条件是否与前面冲突 ,最后输出与前面冲突的数据的个数。
思路:这是一个区间统计的题。我们利用一个sum[]数组保存从某点到其祖先节点距离。注意需要对所有值统计设置相同的初值,但初值的大小一般没有影响。
对区间[l, r]进行记录时,实际上是对 (l-1, r]操作,即l = l - 1。
剩下的就是一个转移的理解,可以看这个 https://www.cnblogs.com/liyinggang/p/5327055.html。
截下屏看下。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,m,a,b,d,ans;
int fa[maxn];
int cnt[maxn];
void init()
{
for(int i=;i<=n;i++)
{
fa[i]=i;
cnt[i]=;
}
ans=;
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
{
int t=fa[x];
fa[x]=findd(fa[x]);
cnt[x]+=cnt[t];
return fa[x];
}
}
bool join(int x,int y,int d)
{
int fx=findd(x),fy=findd(y);
if(fx==fy)
{
if(cnt[x]-cnt[y]!=d)
{
// cout<<"666"<<endl;
return true;
}
}
else
{
// if(fx<fy)
// {
fa[fx]=fy;
cnt[fx]=-cnt[x]+cnt[y]+d;
// }
// else
// {
// fa[fy]=fx;
// cnt[fy]=-cnt[y]+cnt[x]-d;
// }
}
return ;
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
init();
while(m--)
{
scanf("%d %d %d",&a,&b,&d);
a--;
if(join(a,b,d))
ans++;
// for(int i=0;i<=n;i++)
// cout<<fa[i]<<" ";
// cout<<endl;
}
printf("%d\n",ans);
}
return ;
}
E - 食物链 POJ - 1182
现有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
以下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
题意:看题面很好理解的了。
思路:经典带权并查集。对于这三种种类,同类可以用0表示,其他两种分别用1表示该结点被父节点吃,2表示该节点吃父节点。 (要注意这个不是随便分配的,要根据题意推导)
该题之所以能用并查集进行路径压缩,是因为存在A吃B,B吃C,C吃A的三角关系。
这是我们能在路径压缩中使用num[x] = (num[x] + num[fa]) % 3和更新时使用num[fb] = (3 - num[v] + num[u] + (p - 1)) % 3的原因(否则就是一种链式关系了)。
可以看上一题的内容,那个向量的内容,都是一样的。路径压缩的时候更新关系和合并的时候更新关系
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,k,d,x,y,ans;
int fa[maxn],relation[maxn];
void init()
{
for(int i=;i<=n;i++)
{
fa[i]=i;
relation[i]=;
}
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
{
int temp=findd(fa[x]);
relation[x]=(relation[x]+relation[fa[x]]+)%;
fa[x]=temp;
return fa[x];
}
}
void join(int d,int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
{
fa[fx]=fy;
relation[fx]=(-relation[x]+d+relation[y]+)%;
}
else
{
if((relation[x]-relation[y]+)%!=d)
ans++;
}
} int main()
{
scanf("%d %d",&n,&k);
ans=;
init();
while(k--)
{
scanf("%d %d %d",&d,&x,&y);
if(x>n||y>n)
{
ans++;
continue;
}
if(d==&&x==y)
{
ans++;
continue;
}
join(d-,x,y);
}
printf("%d\n",ans);
return ;
}
G - Supermarket POJ - 1456
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80.
Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products.
Input
Output
Sample Input
4 50 2 10 1 20 2 30 1 7 20 1 2 1 10 3 100 2 8 2
5 20 50 10
Sample Output
80
185
题意:买卖N件东西,每件东西都有个截止时间,在截止时间之前买都可以,而每个单位时间只能买一件。问最大获利。
思路:先用sort快排,把最值钱的商品放在第一个,然后先从当前最值钱的开始算,如果当天可以卖的话,就拿一天卖掉,
如果有商品占了那一天,就往前一天寻找,并查集在这里就作为最靠近其保质期当天的那一天,如果其根为0,则表示该商品没有空闲的天卖出。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=;
int n;
int ans;
int fa[maxn];
struct Node
{
int p,d;
}node[maxn];
bool cmp(Node a,Node b)
{
return a.p>b.p;
}
int findd(int x)
{
if(fa[x]==-)
return x;
else
{
fa[x]=findd(fa[x]);
return fa[x];
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=;i<=n;i++)
scanf("%d %d",&node[i].p,&node[i].d);
sort(node+,node++n,cmp);
memset(fa,-,sizeof(fa));
ans=;
for(int i=;i<=n;i++)
{
int temp=findd(node[i].d);
if(temp>)
{
ans+=node[i].p;
fa[temp]=temp-;
}
}
printf("%d\n",ans);
}
return ;
}
J - A Bug's Life POJ - 2492
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
Output
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! 题意:给定n只虫子 不同性别的可以在一起 相同性别的不能在一起。给你m对虫子 判断中间有没有同性别在一起的;
思路:食物链的简单版,我们可以用rank[x]记录x与其父亲节点的关系, rank[x]=0表同性, rank[x]=1表异性;假设前面的教授判断都是正确的, 若后面存在与前面判断矛盾的数据,那么教授判断有误;
注意输出的格式,坑。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int T,n,m,a,b;
bool flag;
int fa[maxn];
int relation[maxn];
void init()
{
for(int i=;i<=n;i++)
{
fa[i]=i;
relation[i]=;
}
flag=false;
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
{
int temp=findd(fa[x]);
relation[x]=(relation[fa[x]]+relation[x])%;
fa[x]=temp;
return fa[x];
}
}
bool join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
{
fa[fx]=fy;
relation[fx]=(-relation[x]+relation[y]+)%;
}
else
{
if((relation[x]+relation[y])%==)
return true;
}
return false;
}
int main()
{
int casee=;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
init();
while(m--)
{
scanf("%d %d",&a,&b);
if(join(a,b))
flag=true;
}
printf("Scenario #%d:\n",casee++);
if(flag)
printf("Suspicious bugs found!\n\n");
else
printf("No suspicious bugs found!\n\n");
}
return ;
}
L - Connections in Galaxy War ZOJ - 3261
In order to strengthen the defense ability, many stars in galaxy allied together and built many bidirectional tunnels to exchange messages. However, when the Galaxy War began, some tunnels were destroyed by the monsters from another dimension. Then many problems were raised when some of the stars wanted to seek help from the others.
In the galaxy, the stars are numbered from 0 to N-1 and their power was marked by a non-negative integer pi. When the star A wanted to seek help, it would send the message to the star with the largest power which was connected with star A directly or indirectly. In addition, this star should be more powerful than the star A. If there were more than one star which had the same largest power, then the one with the smallest serial number was chosen. And therefore, sometimes star A couldn't find such star for help.
Given the information of the war and the queries about some particular stars, for each query, please find out whether this star could seek another star for help and which star should be chosen.
Input
There are no more than 20 cases. Process to the end of file.
For each cases, the first line contains an integer N (1 <= N <= 10000), which is the number of stars. The second line contains N integers p0, p1, ... , pn-1 (0 <= pi <= 1000000000), representing the power of the i-th star. Then the third line is a single integer M (0 <= M <= 20000), that is the number of tunnels built before the war. Then M lines follows. Each line has two integers a, b (0 <= a, b <= N - 1, a != b), which means star a and star b has a connection tunnel. It's guaranteed that each connection will only be described once.
In the (M + 2)-th line is an integer Q (0 <= Q <= 50000) which is the number of the information and queries. In the following Q lines, each line will be written in one of next two formats.
"destroy a b" - the connection between star a and star b was destroyed by the monsters. It's guaranteed that the connection between star a and star b was available before the monsters' attack.
"query a" - star a wanted to know which star it should turn to for help
There is a blank line between consecutive cases.
Output
For each query in the input, if there is no star that star a can turn to for help, then output "-1"; otherwise, output the serial number of the chosen star.
Print a blank line between consecutive cases.
Sample Input
2
10 20
1
0 1
5
query 0
query 1
destroy 0 1
query 0
query 1
Sample Output
1
-1
-1
-1 题意:给你一些点,还有一些边,每个点上都有一个权值,然后有一些询问,分为两种,
query a 询问与a直接或者间接想连的点中最大权值的是那个点,输出那个点,如果那个点的权值小于等于a的权值,那么就输出-1,还有另一种操作就是destroy a b意思是删除a b的关系。
思路:逆向并查集,把没有删除的边先加入并查集,一个集合内表示连通的,根结点为权值最大的点。然后对于查询离线读入,从最后开始操作,对于删除的点,然后重新加入到并查集中,更新最值。
查询的时候便是查询根结点的值是否大于自身的值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <stack>
#define PI pair<int, int>
using namespace std;
const int maxn=;
int n,m,Q;
int x,y;
int a[maxn],fa[maxn];
struct Node
{
int x,y;
}node[maxn*];
struct Key
{
char s[];
int x,y;
}q[maxn*];
void init()
{
for(int i=;i<=n;i++)
fa[i]=i;
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(a[fx]==a[fy])
{
if(fx<fy)
fa[fy]=fx;
else
fa[fx]=fy;
}
else if(a[fx]<a[fy])
fa[fx]=fy;
else
fa[fy]=fx;
}
int main()
{
int k=;
while(scanf("%d",&n)!=EOF)
{
if(k!=)
printf("\n");
k++;
init();
for(int i=;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%d %d",&node[i].x,&node[i].y);
if(node[i].x>node[i].y)
swap(node[i].x,node[i].y);
}
scanf("%d",&Q);
map<PI, int>ha;
for(int i=;i<=Q;i++)
{
scanf("%s",q[i].s);
if(q[i].s[]=='d')
{
scanf("%d %d",&q[i].x,&q[i].y);
if(q[i].x>q[i].y)
swap(q[i].x,q[i].y);
PI pi=make_pair(q[i].x,q[i].y);
ha[pi]=;
}
else
scanf("%d",&q[i].x);
} for(int i=;i<=m;i++)
{
if(!ha.count(make_pair(node[i].x,node[i].y))) {
join(node[i].x,node[i].y);
}
} stack<int>ans;
for(int i=Q;i>;i--)
{
if(q[i].s[]=='q')
{
int r=findd(q[i].x);
if(a[r]<=a[q[i].x])
ans.push(-);
else
ans.push(r);
}
else
join(q[i].x,q[i].y);
}
while(!ans.empty())
{
printf("%d\n",ans.top());
ans.pop();
}
}
return ;
}
M - 小希的迷宫 HDU - 1272
Input输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。
整个文件以两个-1结尾。
Output对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"Yes",否则输出"No"。
Sample Input
6 8 5 3 5 2 6 4
5 6 0 0 8 1 7 3 6 2 8 9 7 5
7 4 7 8 7 6 0 0 3 8 6 8 6 4
5 3 5 6 5 2 0 0 -1 -1
Sample Output
Yes
Yes
No
思路:并查集与图的结合,要判断图是否连通,即检查新给的两个点的father是否相同但是一开始没有考虑到连通性,要检查根节点的数量,即i==father[i]的点为1即判断该图是否为连通无环图
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,m;
bool flag;
int fa[maxn];
bool vis[maxn];
void init()
{
for(int i=;i<maxn;i++)
{
fa[i]=i;
vis[i]=false;
}
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
fa[fx]=fy;
} int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==-&&m==-)
break;
init();
flag=false;
while()
{
if(n==&&m==)
break;
if(findd(n)==findd(m))
flag=true;
join(n,m);
vis[n]=vis[m]=true;
scanf("%d %d",&n,&m);
}
if(flag)
printf("No\n");
else
{
int cnt=;
for(int i=;i<maxn;i++)
{
if(vis[i]&&fa[i]==i)
cnt++;
}
if(cnt>)
printf("No\n");
else
printf("Yes\n");
}
}
return ;
}
N - Is It A Tree? POJ - 1308
There is exactly one node, called the root, to which no directed edges point.
Every node except the root has exactly one edge pointing to it.
There is a unique sequence of directed edges from the root to each node.
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.
In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not.
Input
Output
Sample Input
6 8 5 3 5 2 6 4
5 6 0 0 8 1 7 3 6 2 8 9 7 5
7 4 7 8 7 6 0 0 3 8 6 8 6 4
5 3 5 6 5 2 0 0
-1 -1
Sample Output
Case 1 is a tree.
Case 2 is a tree.
Case 3 is not a tree. 和上一题一样的思路和解法。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=;
int n,m;
bool flag;
int fa[maxn];
bool vis[maxn];
void init()
{
for(int i=;i<maxn;i++)
{
fa[i]=i;
vis[i]=false;
}
}
int findd(int x)
{
if(x==fa[x])
return fa[x];
else
return fa[x]=findd(fa[x]);
}
void join(int x,int y)
{
int fx=findd(x),fy=findd(y);
if(fx!=fy)
fa[fx]=fy;
} int main()
{
int casee=;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==-&&m==-)
break;
init();
flag=false;
while()
{
if(n==&&m==)
break;
if(findd(n)==findd(m))
flag=true;
join(n,m);
vis[n]=vis[m]=true;
scanf("%d %d",&n,&m);
}
if(flag)
printf("Case %d is not a tree.\n",casee++);
else
{
int cnt=;
for(int i=;i<maxn;i++)
{
if(vis[i]&&fa[i]==i)
cnt++;
}
if(cnt>)
printf("Case %d is not a tree.\n",casee++);
else
printf("Case %d is a tree.\n",casee++);
}
}
return ;
}