UVA1391宇宙飛行士(ACM-ICPC 2006 Europe-Central)(2-SAT問題、出力計画)

ここに画像の説明を挿入
タイトルにはA、B、Cの3つの状態がありますが、各個人は2つの状態しか選択できません。明らかに2-SATです。画像を作成するときに、i + nとしてA(またはB)を選択し、iとしてCを選択するとします。 ;最初に、2人が嫌いな場合、1人がCを選択し、もう1人は(x、y + n)と(y、x + n)の両サイドがあってももう一方を選択する必要があります。2人が同じタイプの場合、追加する必要があります。上限は、2人が同時にAを選択する(またはBを同時に選択する)ことを防止し、2つのサイド(x + n、y)、(y + n、x)を接続します。tarjan
が最後に回答を出力する場合、実行する必要はありません。一方はトポロジー的にソートされます。タージャンで強く接続されたコンポーネントが色付けされる順序はトポロジー的な順序であるため、col(i)<col(i + n)の場合はA(またはB)を選択し、それ以外の場合はCを選択することを意味します。

ピットに注意してください。2SAT問題で計画を出力する必要がある場合、コード出力がサンプルと異なっていても、2SAT問題には多くの解決策があるため、心配しないでください。その結果、私のサンプルは良くありません。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;
typedef long long ll;
const int N = 5000007, M = 5000007, INF = 0x3f3f3f3f;

int n, m;
int dfn[N], low[N], num;
int head[N], ver[M], nex[M], tot;
int stk[N], top;
bool ins[M];
int scc_cnt;
int color[N];

void init()
{
    
    
    memset(head, -1, sizeof head);
    memset(dfn, 0, sizeof dfn);
    memset(low, 0, sizeof low);
    memset(color, 0, sizeof color);
    tot = num = scc_cnt = 0;
}

int age[N];

void add(int x, int y)
{
    
    
    ver[tot] = y;
    nex[tot] = head[x];
    head[x] = tot ++ ;
}

void tarjan(int x)
{
    
    
    dfn[x] = low[x] = ++num;
    stk[++ top] = x;
    ins[x] = 1;
    for(int i = head[x]; ~i; i = nex[i]){
    
    
        int y = ver[i];
        if(!dfn[y]){
    
    
            tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if(ins[y])
            low[x] = min(low[x], dfn[y]);
    }

    if(low[x] == dfn[x]){
    
    
        int y;
        ++scc_cnt;
        color[x] = scc_cnt;
        do{
    
    
            y = stk[top -- ];
            ins[y] = false;
            color[y] = scc_cnt;
        }while(x != y);
    }
}
int main()
{
    
    
    while(scanf("%d%d", &n, &m)!= EOF && n + m){
    
    
        init();
        int sum = 0;
        for(int i = 1;i <= n; ++ i){
    
    
            scanf("%d", &age[i]);
            sum += age[i];
        }
        for(int i = 1; i <= n; ++ i){
    
    
            age[i] = (age[i] * n >= sum);
        }
        for(int i = 1; i <= m; ++ i){
    
    
            int p, q;
            scanf("%d%d", &p, &q);
            //i + n : A / B
            //i : B / C
            if(age[p] == age[q])add(p + n, q), add(q + n, p);
            add(p, q + n),add(q, p + n);
        }

        for(int i =  1; i <= 2 * n; ++i){
    
    
            if(!dfn[i])
                tarjan(i);
        }
        bool flag = 1;
        for(int i = 1; i <= n; ++ i){
    
    
            if(color[i] == color[i + n]){
    
    
                puts("No solution."), flag = 0;
                break;
            }
        }

        if(!flag)continue;
        for(int i = 1; i <= n; ++ i){
    
    
            //谁小选谁 i + n 小的话,就是 i + n : A / B
            if(color[i] > color[i + n]){
    
    
                if(age[i])//根据题意1为大于平均值x,选A,B中的A
                    puts("A");
                else puts("B");
            }
            else puts("C");
        }
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_45697774/article/details/108720193