有一群旅行爱好者,有一天,他们带回了n只蝴蝶回来。他们相信每一只都属于两个不同种类中的一种,为了讨论方便,我们称它们为A与B。他们想把n只标本分成两组——一些属于A且一些属于B——但是直接标记任何一个标本对于他们是非常困难,因此他们决定采用下面的方法。
对每对标本i和j,他们细心地把它们放到一起研究。如果他们以自己的判断足以确信,那么他们把这对蝴蝶标记为“相同”(这意味着他们相信这两只来自同一类)或者是“不同”(这意味着他们相信这两只来自不同的类)。他们也可以对某些标本判断不出来而弃权,在这种情况下,我们称这对标本是不明确的。
现在他们有n只标本的集合,还有对那些没有弃权的标本对的m个判断的集合(“相同”或者“不同”)。他们想知道这个数据与每只蝴蝶来自A和B中的一个类的想法是否一致。更具体地说,如果对每对蝴蝶按照下述方式标记A或B是可能的,即对每个标为“相同”的(i,j)对,就是i与j有相同标记的情况;对每个标为“不同”的(i,j)对,就是i与j有不同标记的情况。那么我们可以说这m个判断是一致的。他们正在冥思苦想自己的判断是否是一致的。请你帮他们设计合理的算法解决该问题。
3 3 0 1 0 1 2 1 0 2 1 3 3 0 1 0 1 2 1 0 2 0样例输出
YES
NO
解题思路:
整体思路就是先利用相同种类的节点建立一个树形的关系,然后判断不同种类的节点和这个树存不存在矛盾,如果存在那么就输出NO
1.把0-n-1看作n个节点,每个节点设置一个父节点,初始化的时候每个节点父节点的值都是它本身,
2.输入的时候如果两个节点属于同一类,那么判断他们的父节点是否值相同,如果不用,则将父节点值较小的赋给父节点值大的,定义findfather(int a)函数,来递归找a的父节点值,递归的结束条件是findfather(a) == a,这样分类相同的节点最终肯定都指向同一个节点。
3.输入的时候如果两个节点不同类,则先存在二维数组中,
4.最后遍历二维数组,如果第三列等于1,就找到这两个节点的父节点,如果父节点值相同,那么就输出NO,记录每个父节点的值,如果有大于两类的值,也还有像上例第一例的情况,2没有用来建立树,那么它的父节点还是2,不会跟其他节点父节点值相同,就不会影响结果。
#include
#include
#include
#include
using namespace std;
int father[1005];//存储父节点
int a[100500][4];//存储二维数组
int panduan[1005];
int findfather(int x)//递归找父节点
{
if(x == father[x]) { //结束递归条件
return x;
}
else {
x = father[x];
findfather(x);
}
}
int main(){
int n,m,i,flag,pan;
while(~scanf("%d %d",&n,&m)){
pan=0;
memset(panduan, 0, sizeof(panduan));
flag=1;
for (i = 0; i < n; i++) {
father[i] = i; //初始化父节点值
}
for (i = 0; i < m; i++) {
scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
if(!a[i][2]){ //如果属于同一类
int xx = findfather(a[i][0]);
int yy = findfather(a[i][1]);
if (xx!=yy) { //将小值赋给大值,保证指向同一个节点
if(xx>yy)father[a[i][0]] = yy;
else father[a[i][1]] = xx;
}
}
}
for(i=0;i2){printf("NO\n");flag=0;break;} //父节点相同产生矛盾,输出NO
}
}
if(flag==1)printf("YES\n");
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int father[1005];//存储父节点
int a[100500][3];//存储二维数组
int panduan[1005];
int findfather(int a) //优化递归
{
if(father[a] != a)
father[a] = findfather(father[a]);
return father[a];
}
int main(){
int n,m,i,flag,pan;
while(~scanf("%d %d",&n,&m)){
pan=0;
memset(panduan, 0, sizeof(panduan));
flag=1;
for (i = 0; i < n; i++) {
father[i] = i; //初始化父节点值
}
for (i = 0; i < m; i++) {
scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
if(!a[i][2]){ //如果属于同一类
int xx = findfather(a[i][0]);
int yy = findfather(a[i][1]);
if (xx!=yy) { //将小值赋给大值,保证指向同一个节点
if(xx>yy)father[a[i][0]] = yy;
else father[a[i][1]] = xx;
}
}
}
for(i=0;i2){printf("NO\n");flag=0;break;} //父节点相同产生矛盾,输出NO
}
}
if(flag==1)printf("YES\n");
}
return 0;
}