How Many Tables HDU - 1213
https://cn.vjudge.net/contest/283640#problem/C
题意:ignatius过生日,客人来到,他想知道他需要准备多少张桌子。然而一张桌子上面只能坐上相互熟悉的人,
其中熟悉可定义成为A与B认识,B与C认识,我们就说A,B,C相互熟悉 。例如A与B熟悉and B与C熟悉,D与E熟悉,此时至少需要两张桌子。
输入:t表示样例个数,n表示朋友个数,朋友从1到n编号,m表示已知相互了解的对数,接着m行。每行表示相互熟悉的编号
输出:至少需要准备的桌子个数
//简单并查集
#include<stdio.h>
int pre[1200];//储存每个节点的根节点
int root(int a)//查询根节点
{
if(a == pre[a])
return a;
return pre[a] = root(pre[a]);//路径压缩,把a点的根节点赋值为这个集合的根节点,在查询时减少递归次数,会更快
}
void join(int a, int b)//合并操作
{
if(root(a) != root(b))
{
pre[root(a)] = b;//a,b的根节点不相同,则吧其中一个的根节点当做另一个的根节点
}
}
int main()
{
int i, n, m, t, num,aa,bb;
scanf("%d",&t);
while(t --)
{
num = 0;
scanf("%d %d",&n, &m);
for(i = 1; i <= n; i ++)
{
pre[i] = i;//首先将每个节点的根节点赋值为自己
}
while(m --)
{
scanf("%d %d",&aa, &bb);
join(aa, bb);//将两个节点连接
}
for(i = 1; i <= n; i ++)
{
if(pre[i] != i)//查询有多少集合,也就是有多少节点的根节点是自己
{
num ++;
}
}
printf("%d\n",n-num);
}
return 0;
}
How Many Answers Are Wrong
https://cn.vjudge.net/problem/HDU-3038
题目大意:有M个数,不知道它们具体的值,但是知道某两个数之间(包括这两个数)的所有数之和,现在给出N个这样的区间和信息,需要判断有多少个这样的区间和与前边已知的区间和存在矛盾。例如给出区间和[1,4]为20,[3,4]为15,再给出[1,2]为30,显然这个[1,2]的值就有问题,它应该为20-15=5。
//带权并查集
#include<stdio.h>
int pre[200009],sum[200009];//每个节点的根节点,根节点到此点的区间和
int find(int a)
{
if(a ==pre[a])
return a;
else
{
int root = find(pre[a]);
sum[a] += sum[pre[a]];//路径压缩的同时,加上每一步压缩所增加的权值
return pre[a] = root;
}
}
int main()
{
int i,m,n,l,r,v,ans;
while(scanf("%d %d",&n,&m)!= EOF)
{
for(i = 0; i <= n; i ++)
{
pre[i] = i;//根节点赋值为自身
sum[i] = 0;//赋储值为0
}
ans = 0;//出错的信息数
while(m --)
{
scanf("%d %d %d",&l, &r,&v);//l点到r点的区间和
l --;//l要减一,这样可以让类似【1,5】【6,10】这样的区间可以合并
int fl = find(l);
int fr = find(r);
if(fl == fr)//如果两点的根节点相同,那么他们之间的权值差已经可以确定
{
if(sum[r]-sum[l] != v)//若与之前的结论矛盾,错误数+1
ans ++;
}
else//否则,进行合并操作
{
pre[fr] = fl;
sum[fr] = sum[l] - sum[r] + v;//l到fr的两条路的权值应该相同,即sum[l] + sum[fr] == s + sum[r],具体可以画图
}
}
printf("%d\n",ans);
}
return 0;
}