1. 程式人生 > >HihoCoder 1638 : 小Hi的天平 (2-sat+並查集)

HihoCoder 1638 : 小Hi的天平 (2-sat+並查集)

並查集 整數 個數 std blog 方便 submit 現在 否則

描述

小Hi給小Ho郵寄了一個天平。收到天平後,小Ho想知道天平在運輸過程中是否損壞,為此它準備了A類物品和B類物品共n個(可能只有A類物品,也可能只有B類物品),但無法確定一個物品是哪一類。A類物品的質量都相同,B類物品的質量也相同,但A類物品與B類物品的質量不同。現將n個物品從1到n編號,用天平進行m次測量,每次從n個物品中取i和j兩個物品,測量後可以知道物品i和物品j質量是否相同。

現在小Ho想知道能否根據測量結果判定天平是壞的,如果能確定,最早是第幾次測量確定的,你能幫幫他嗎?

輸入

第一行一個數字T,代表數據組數。1<=T<=5。
對於每組數據:
第一行兩個整數n,m,分別代表A類、B類物品的總數和測量次數。2<=n<=10000,1<=m<=300000。

接下來m行,每行三個數字x,u,v。x=0代表物品u與物品v質量相等,x=1代表質量不等。

輸出

對於每組數據:
若不能確定天平是壞的,則輸出一行“great”。
否則,輸出兩行。
第一行輸出“sad”。
第二行輸出一個數字p,代表最早第p次測量確定了天平是壞的。

樣例輸入
1
2 2
0 1 2
1 1 2
樣例輸出
sad
2

思路:對於每一個物品i,我們可以假設i是R色,則i+n是B色,然後2-sat驗證。但是這樣的話二分不方便。

所以改用並查集來實現:對於每一個關系,如果相同,則合並 u和v,u+n和v+n;否則合並u和v+n,v+u+n,知道出現矛盾。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<string>
const int maxn=20030;
using namespace std;
int m,n,x,u,v;
int flag=1;
int par[maxn],rnk[maxn];
void init( int n )
{
    for (int i=0;i<=n;i++){
        par[i]
=i; rnk[i]=0; } } int find( int x ) { return x==par[x]?x:find(par[x]); } void unite( int x, int y ) { x=find(x); y=find(y); if(x==y) return; if(rnk[x]<rnk[y]) par[x]=y; else{ par[y]=x; if (rnk[x]==rnk[y]) rnk[x] ++; } } bool same( int x, int y ) { return find(x)==find(y); } int main() { int T; scanf("%d",&T ); while (T--){ scanf("%d%d",&n,&m ); init(n*2+10); flag=1; for(int i=1;i<=m;++i){ scanf("%d%d%d",&x,&u,&v ); if (flag){ if(x==0){ if(same(u,v+n)){ puts("sad"); printf("%d\n",i); flag = 0; } else{ unite(u,v); unite(v+n,u+n); } } else{ if (same(u,v)||same(u+n,v+n)){ puts("sad"); printf( "%d\n",i); flag = 0; } else{ unite(u,v+n); unite(u+n,v); } } } } if (flag) puts("great"); } return 0; }

HihoCoder 1638 : 小Hi的天平 (2-sat+並查集)