[種類の]食物連鎖のPOJ 1182 ---互いに素セット||思考+互いに素セット
トピック出典:入力するようにクリックして、[POJ 1182 -フードチェーン]
説明
動物界のAの動物の3種類があり、Bは、Cは、動物の食物連鎖の3つのタイプが面白い環を構成します。食品B、BはAを食べるC、Cを食べます
動物の前N、1-Nの数。各動物は親切でA、B、Cであるが、我々は最終的にはそれを知らないどのような種類のです。
:これは、N説明から成るこの栄養動物の2つのバージョンを用いて行った
、最初の引数が「1 X Y」であるXを表し、Yは類似しています。
2番目の引数が「2 X Y」であり、Xは食べる表しY.
上記の二つの文、文によって、一つの文章とNの動物のためのこの人は、この文いくつかの真の、いくつかの偽のK、Kを避けます。以下の三つの言葉の一つ、この文は嘘である場合には、真実はそうです。
現在の真の場合1)、次いで前の競合のいくつかは、嘘である;
2)、次いで、現在のXまたはYがNよりも大きい場合、嘘である;
3)Xが食べる表し、現在のXは、嘘です。
ジョブは、N(1 <= N <=に従って与えられ 50,000) とKワード(0 <= K <=10万 )、 出力嘘の総数。
入力
二つの整数N及びKの最初の行は、空白で区切られました。
Kザは、3行以下、各Dは、引数の型を示す二つの数字の間のスペースで区切られた正の整数D、X、Y、です。
D = 1の場合は、XとYが類似していることを示しています。
D = 2の場合、Xは食べる表しY.
出力
唯一の嘘の数を表す1つの整数。
サンプル入力
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5
サンプル出力
3
問題解決のためのアイデア1
第1のYが範囲外である、Xを決定し、範囲外に等しいか、または間違っている必要があります。
ABC三つのグループは、0-N-1でそれぞれ表される、N- 2N-1,2n-3N-1。
配列D入力、X、Yを分析するステップと、
D = 1の場合:
それは嘘である場合にのみ、xとy + nは、xとy + 2Nを決定すること、すなわち、均一でありません。それは、X、Yの周りでない場合、X + N、 Y + N; X + 2N、Y + 2N 一つに合わせました。
場合D = 2:
それは嘘である場合にのみ、xとy、xとy + 2nとを決定するには、即ち、均一でありません。それは、X、N Y +に対して約ない場合、X + N、Y + 2N; X + 2Nは、yがマージされます。
ACコード1:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
const int MAXN = 5e4+5;
int pre[3*MAXN];
void init(int n)
{
for(int i=0;i<=3*n;i++)
pre[i]=i;
}
int _find(int x)
{
if(x==pre[x]) return x;
return pre[x]=_find(pre[x]);
}
void unite(int x,int y)
{
x=_find(x);
y=_find(y);
if(x!=y) pre[x]=y;
}
bool compare(int x,int y)
{
return _find(x)==_find(y);
}
int main()
{
SIS;
int n,m,a,b,d,ans=0;
scanf("%d%d",&n,&m);
init(n);
while(m--)
{
scanf("%d%d%d",&d,&a,&b);
if(a>n || b>n || (d==2&a==b)) ans++;
else if(d==1)
{
if(compare(a,b+n) ||compare(a,b+2*n)) ans++;
else
{
unite(a,b);
unite(a+n,b+n);
unite(a+2*n,b+2*n);
}
}
else
{
if(compare(a,b) || compare(a,b+2*n)) ans++;
else
{
unite(a,b+n);
unite(a+n,b+2*n);
unite(a+2*n,b);
}
}
}
cout << ans << endl;
return 0;
}
問題解決のためのアイデア2
配列arrを流れる電流ノードと親ノードとの関係を示す互いに素なセットタイプ、。
xがyを食べよう、次いで動物の三種類があるため、大きな1の右よりのY値をX、重みが0,1,2 3分割されなければなりません。重みが2である場合は0がルートノードであり、ノードは、1の重みを持っている場合、それはノードが食べるためにルートノードであることを示し、2は1(1 2 1よりも大きい)、として食べる表します関係サイクル食べるために3匹の動物は、食べ2 0で、です。
ARR [X] == 0:現在のノードと親ノード類似
ARR [X] == 1:食べるために現在の節点の親ノード
食べるために、現在のノードの親ノードを:ARR [X] == 2
のルックアップのセットを組み合わせることによって更新されARR配列。
ACコード2:
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 5e4+5;
int pre[MAXN],arr[MAXN];
int n,m,a,b,d,ans=0;
void init(int n)
{
for(int i=0;i<=n;i++)
pre[i]=i,arr[i]=0;
}
int _find(int x)
{
if(x==pre[x]) return x;
int p=pre[x];
pre[x]=_find(pre[x]);
arr[x]=(arr[p]+arr[x])%3;
return pre[x];
}
void unite()
{
int x=_find(a);
int y=_find(b);
pre[x]=y;
arr[x]=(arr[b]-arr[a]+d+2)%3;//d-1 + 3
}
bool compare()
{
if(a>n || b>n) return false;
else if(d==2 && a==b) return false;
int x=_find(a);
int y=_find(b);
if(x==y && (arr[a]-arr[b]+3)%3!=d-1) return false;
return true;
}
int main()
{
scanf("%d%d",&n,&m);
init(n);
while(m--)
{
scanf("%d%d%d",&d,&a,&b);
if(compare()) unite();
else ans++;
}
cout << ans << endl;
return 0;
}