POJ 1182并查集的经典运用

tag的取值:1表示x吃px,-1表示px吃x,0表示x与px同类

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

typedef struct {
    int parent;
    int tag;
}Node;

vector<Node> nodes;
int n, k;

void MakeSet()
{
    nodes.resize( n+10 );
    for(int i = 0; i < nodes.size(); ++i)
    {
	nodes[i].parent = i;
	nodes[i].tag = 0;
    }
}

int FindSet(int index, int& steps)
{
    if( nodes[index].parent == index )
	return index;
    else 
    {
	steps += nodes[index].tag;
	nodes[index].parent = FindSet( nodes[index].parent, steps );
	steps %= 3;
	switch( steps )
	{
	    case -2:
		nodes[index].tag = 1;
		break;
	    case 2:
		nodes[index].tag = -1;
		break;
	    default:
		nodes[index].tag = steps;
	}
	return nodes[index].parent;
    }
}

void Union(int r1, int r2, int t)
{
    nodes[r2].parent = r1;
    nodes[r2].tag = t;
}

int main()
{
    cin >> n >> k;
    MakeSet();
    int ans = 0;
    for(int i = 0; i < k; ++i)
    {
	int t, x, y;
	cin >> t >> x >> y;
	if( x > n || y > n )
	    ++ans;
	else if(t == 2 && x == y)
	    ++ans;
	else 
	{
	    int d1 = 0, d2 = 0;
	    int r1 = FindSet(x, d1);
	    int r2 = FindSet(y, d2);
	    if( r1 == r2 )
	    {
		if(nodes[x].tag == nodes[y].tag && t != 1)
		    ++ans;
		if(t == 2)
		{
		    int t1 = nodes[x].tag;
		    int t2 = nodes[y].tag;
		    if( (t1==-1&&t2==0) 
			    || (t1==-1&&t2==1) 
			    || (t1==1&&t2==-1) )
			++ans;
		}
	    }
	    else 
	    {
		int d = nodes[x].tag - 1 - nodes[y].tag;
		if( d <= -2 )
		    d += 3;
		else if( d >= 2 )
		    d -= 3;
		Union(r1, r2, d);
	    }
	}
    }
    cout << ans << endl;
    return 0;
}

tag为-1,0,1时,代码写起来挺费劲的。借鉴了网上的代码,将tag的取值改为0,1,2;其中2表示px吃x,0,1取值含义保持不变

#include <iostream>
#include <vector>
#include <cstdio>

using namespace std;

class Node
{
    public:
	int parent;
	int link;
	int rank;
	Node(int p=0, int l=0, int r=0):parent(p), link(l), rank(r){
	};
};

vector<Node> nodes;
int n, k;

void MakeSet()
{
    nodes.resize( n+1 );
    for(int i = 1; i <= n; ++i)
	nodes[i] = Node(i) ;
}

int FindSet(int i)
{
    if( nodes[i].parent == i )
	return i;
    int p = nodes[i].parent;
    nodes[i].parent = FindSet( nodes[i].parent );
    nodes[i].link = (nodes[i].link + nodes[p].link)%3;
    return nodes[i].parent;
}

void Union(int x, int y, int link)
{
    int rx = FindSet(x);
    int ry = FindSet(y);
    if( nodes[rx].rank < nodes[ry].rank )
    {
	nodes[rx].parent = ry;
	nodes[rx].link = (3 - nodes[x].link + link + nodes[y].link)%3;
    }
    else 
    {
	nodes[ry].parent = rx;
	if( nodes[rx].rank == nodes[ry].rank )
	    nodes[rx].rank += 1;
	nodes[ry].link = (6 - nodes[y].link - link + nodes[x].link)%3;
    }
}

int main()
{
    int ans = 0;
    scanf("%d%d", &n, &k);
    MakeSet();
    for(int i = 0; i < k; ++i)
    {
	int l, x, y;
	scanf("%d%d%d", &l, &x, &y);
	--l;
	if(x > n || y > n)
	    ++ans;
	else if(l == 1 && x == y)
	    ++ans;
	else if( FindSet(x) == FindSet(y) )
	{
	    if( (l+nodes[y].link)%3 != nodes[x].link )
		++ans;
	}
	else 
	{
	    Union(x, y, l);
	}
    }
    printf("%d\n", ans);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值