1. 程式人生 > >【HDU 1811】 Rank of Tetris 並查集+拓撲

【HDU 1811】 Rank of Tetris 並查集+拓撲

題目連結:傳送門

 

中文題目就不闡述題意了,我最開始的想法是種類並查集,但是細想一下,發現並不可行,因為題目沒有告訴有多少型別。

 

做法:關鍵問題是處理等號的兩個點,其實兩個點相等,就相當於這兩個人的排名是一樣的,我們用並查集搞定這麼些個相等排名的點,之後把有全序關係的點入度入圖,然後拓撲排序走一發,如果到最後所有點的度都變成了0,那麼這個圖就滿足OK的條件,否則屬於衝突。如果最後所有點的度都變成了0,但是拓撲排序期間有兩個點同時度為0,那麼說明資訊不夠全。
 

①先用並查集將相等的關係合併

    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        int ind[10005]= {0},peo=m;      ///最終判斷能否去掉所有邊。(最終所有點的入度都為0)
        bool vis[10005]= {0};
        vector<int>load[10005];
        for(int i=0; i<n; i++)
            p[i]=i;
        for(int i=1; i<=m; i++)
        {
            scanf("%d %c %d",&text[i].s,&text[i].re,&text[i].e);
            if(text[i].re=='=')
            {
                peo--;      ///相等的邊去掉,其沒有意義
                p[f(text[i].s)]=f(text[i].e); ///讓所有相等的點(排名相同的人),用一個人代替。
            }
        }

②利用關係入度

        for(int i=1; i<=m; i++)
        {
            int x=f(text[i].s);
            int y=f(text[i].e);
            if(text[i].re=='>')
            {
                load[x].push_back(y);
                ind[y]++;
            }
            if(text[i].re=='<')
            {
                load[y].push_back(x);
                ind[x]++;
            }
        }

③拓撲排序+輸出判斷

        queue<int>ranks;    ///BFS拓撲
        int sign=0;///入度為0的點最多一個
        int ff1=1;  ///判斷變數 sign
        for(int i=0; i<n; i++)
        {
            if(!vis[i]&&f(i)==i&&ind[i]==0)///入隊的條件
            {
                sign++;
                vis[i]=1;
                ranks.push(i);
            }
        }
        if(sign>1)
            ff1=0;
        while(ranks.size())
        {
            sign=0;
            int w=ranks.front();
            ranks.pop();
            int d=load[w].size();
            for(int i=0; i<d; i++)
            {
                peo--;      ///有關係的邊去除。
                int e=load[w][i];
                ind[e]--;    ///入度減 1
                if(!vis[e]&&f(e)==e&&ind[e]==0)
                {
                    sign++;
                    vis[e]=1;
                    ranks.push(e);
                }
            }
            if(sign>1)
                ff1=0;
        }
        if(peo!=0)      ///判斷條件
            printf("CONFLICT\n");
        else if(ff1==0)
            printf("UNCERTAIN\n");
        else
            printf("OK\n");

完整的程式碼

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<set>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

struct node
{
    int s;
    char re;
    int e;
} text[20005];

int p[10005];

int f(int x)
{
    return p[x]==x?x:p[x]=f(p[x]);
}

int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        int ind[10005]= {0},peo=m;      ///最終判斷能否去掉所有邊。(最終所有點的入度都為0)
        bool vis[10005]= {0};
        vector<int>load[10005];
        for(int i=0; i<n; i++)
            p[i]=i;
        for(int i=1; i<=m; i++)
        {
            scanf("%d %c %d",&text[i].s,&text[i].re,&text[i].e);
            if(text[i].re=='=')
            {
                peo--;      ///相等的邊去掉,其沒有意義
                p[f(text[i].s)]=f(text[i].e);       ///讓所有相等的點(排名相同的人),用一個人代替。
            }
        }
        for(int i=1; i<=m; i++)
        {
            int x=f(text[i].s);
            int y=f(text[i].e);
            if(text[i].re=='>')
            {
                load[x].push_back(y);
                ind[y]++;
            }
            if(text[i].re=='<')
            {
                load[y].push_back(x);
                ind[x]++;
            }
        }
        queue<int>ranks;    ///BFS拓撲
        int sign=0;///入度為0的點最多一個
        int ff1=1;  ///判斷變數 sign
        for(int i=0; i<n; i++)
        {
            if(!vis[i]&&f(i)==i&&ind[i]==0)///入隊的條件
            {
                sign++;
                vis[i]=1;
                ranks.push(i);
            }
        }
        if(sign>1)
            ff1=0;
        while(ranks.size())
        {
            sign=0;
            int w=ranks.front();
            ranks.pop();
            int d=load[w].size();
            for(int i=0; i<d; i++)
            {
                peo--;      ///有關係的邊去除。
                int e=load[w][i];
                ind[e]--;    ///入度減 1
                if(!vis[e]&&f(e)==e&&ind[e]==0)
                {
                    sign++;
                    vis[e]=1;
                    ranks.push(e);
                }
            }
            if(sign>1)
                ff1=0;
        }
        if(peo!=0)      ///判斷條件
            printf("CONFLICT\n");
        else if(ff1==0)
            printf("UNCERTAIN\n");
        else
            printf("OK\n");
    }
    return 0;
}

參考的部落格:https://blog.csdn.net/mengxiang000000/article/details/50755092