HDU 1814 Peaceful Commission / HIT 1917 Peaceful Commission /CJOJ 1288 和平委員會

HDU 1814 Peaceful Commission / HIT 1917 Peaceful Commission /CJOJ 1288 和平委員會(2-sat模板題)

Description

The Public Peace Commission should be legislated in Parliament of The Democratic Republic of Byteland according to The Very Important Law. Unfortunately one of the obstacles is the fact that some deputies do not get on with some others.

The Commission has to fulfill the following conditions:
1.Each party has exactly one representative in the Commission,
2.If two deputies do not like each other, they cannot both belong to the Commission.

Each party has exactly two deputies in the Parliament. All of them are numbered from 1 to 2n. Deputies with numbers 2i-1 and 2i belong to the i-th party .

Task
Write a program, which:
1.reads the number of parties and the pairs of deputies that are not on friendly terms,
2.decides whether it is possible to establish the Commission, and if so, proposes the list of members,
3.writes the result

Input

In the first line there are two non-negative integers n and m. They denote respectively: the number of parties, 1 <= n <= 8000, and the number of pairs of deputies, who do not like each other, 0 <= m <=2 0000. In each of the following m lines there is written one pair of integers a and b, 1 <= a < b <= 2n, separated by a single space. It means that the deputies a and b do not like each other.
There are multiple test cases.

Output

The text should contain one word NIE (means NO in Polish), if the setting up of the Commission is impossible. In case when setting up of the Commission is possible the file should contain n integers from the interval from 1 to 2n, written in the ascending order, indicating numbers of deputies who can form the Commission. Each of these numbers should be written in a separate line. If the Commission can be formed in various ways, your program may write mininum number sequence.

Sample Input

3 2
1 3
2 4

Sample Output

1
4
5

Http

HDU:https://vjudge.net/problem/HDU-1814
HIT:https://vjudge.net/problem/HIT-1917
CJOJ:http://oj.changjun.com.cn/problem/detail/pid/1288

Source

2-sat

翻譯(By CJOJ)

根據憲法,Byteland民主共和國的公衆和平委員會應該在國會中通過立法程序來創立。 不幸的是,由於某些黨派代表之間的不和睦而使得這件事存在障礙。
此委員會必須滿足下列條件:
每個黨派都在委員會中恰有1個代表,
如果2個代表彼此厭惡,則他們不能都屬於委員會。
每個黨在議會中有2個代表。代表從1編號到2n。 編號爲2i-1和2i的代表屬於第I個黨派。
任務
寫一程序:
輸入黨派的數量和關係不友好的代表對,
計算決定建立和平委員會是否可能,若行,則列出委員會的成員表。

題目大意

有n個組,每組裏有兩個元素,現在給出m對元素不能都選擇的條件,求一個集合使得每組裏面恰好選擇了一個元素且滿足上述m對條件

解決思路

這是一道2-sat的模板題。

我們設i和i’表示一個黨派中的兩個人,那麼如果i與j不能夠共存,則說明若選i則必須選j’,同理,若選j則必須選擇j’。由此,我們可以建邊連圖。對於互相厭惡的兩個代表i,j連邊i->j’j->i’。注意這是有向邊

爲什麼是有向邊呢?

因爲i與j互相厭惡不代表i’與j’互相厭惡,如果連了邊j’->i,那麼意思是選j’必須選i(同時也表示一定不能選i’),但j’與i並不一定互相厭惡,所以連的邊一定是有向邊。

然後就是判斷的方法。因爲題目要求要按字典序輸出,所以對於每一組,我們先檢查標號較小的那個(i),如果不行,再檢查編號大的(i+1)

另外一點需要注意的是,由於要求字典序輸出,所以不能使用Tarjan縮點+拓撲排序的方法,只能用dfs一個一個判斷

代碼

//暴力染色法
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;

#define Other(x) ((x%2==0) ? (x-1) : (x+1) ) //Other(x) 表示與x同黨派的另一個人。這裏用i和i+1來表示同黨派的兩個人(i爲奇數)

const int maxN=16050;
const int inf=2147483647;

int n,m;
int cnt;
vector<int> E[maxN];//用來存放邊
int color[maxN];//存染色時每個點的顏色,0代表還沒有填,1和2分別代表兩種顏色
int Ans[maxN];//臨時存放答案

bool solve();//循環染色
bool dfs(int x);//檢查是否滿足沒有矛盾

int main()
{
    while (cin>>n>>m)
    {
        n=n*2;
        int a,b;
        for (int i=1;i<=n;i++)
            E[i].clear();//因爲HDU上是多組數據,所以每一次都要重新清空
        for (int i=1;i<=m;i++)
        {
            cin>>a>>b;
            E[a].push_back(Other(b));
            E[b].push_back(Other(a));
        }
        if (solve())
        {
            for (int i=1;i<=n;i++)//輸出所有被染成1色的點
                if (color[i]==1)
                    cout<<i<<endl;
        }
        else
            cout<<"NIE"<<endl;
    }
}

bool solve()
{
    memset(color,0,sizeof(color));
    for (int i=1;i<=n;i++)
    {
        if (color[i]!=0)//如果這個點已經被染色(即前面已經給其染過色)
            continue;
        cnt=0;//臨時保存答案的計數器
        if (!dfs(i))//先嚐試把i染成1,若不行則在下面選擇Other(i)
        {
            for (int j=1;j<=cnt;j++)//若要選擇Other(i)則要把之前檢查i是否滿足時用到的數組清空
            {
                color[Ans[j]]=0;
                color[Other(Ans[j])]=0;
            }
            cnt=0;//感謝dsl大佬的查錯,這裏要加cnt=0,雖然說不加程序並不會出錯,但是會浪費一堆空間,若數據大時可能會出問題
            if (!dfs(Other(i)))//如果把Other(i)也染成1也不滿足,說明無解
                return 0;
        }
    }
    return 1;
}

bool dfs(int x)
{
    if (color[x]==1)//如果該點已被染成1,說明滿足並返回
        return 1;
    if (color[x]==2)//如果該點已被染成2,說明矛盾
        return 0;
    color[x]=1;//把這一點染成1
    color[Other(x)]=2;//把其相對的點染成2
    cnt++;
    Ans[cnt]=x;//把這一點放入Ans中,方便後面清空
    for (int i=0;i<E[x].size();i++)//傳遞染色
        if (!dfs(E[x][i]))//如果傳遞失敗,說明矛盾
            return 0;
    return 1;
}
發佈了33 篇原創文章 · 獲贊 4 · 訪問量 8279
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章