[種類の]食物連鎖のPOJ 1182 ---互いに素セット||思考+互いに素セット

[種類の]食物連鎖の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;
}
发布了412 篇原创文章 · 获赞 135 · 访问量 4万+

おすすめ

転載: blog.csdn.net/qq_41879343/article/details/104164102