题目链接:
HDU 1824 Let's go home (2-SAT)

题意分析:
n支队伍,m个关系。满足:1.队伍里面,队长和其余两名队员两者中必须有一个要留下来;2.关系中,A队员留下B队员就得离开,B队员留下,A队员就要离开。问:能否合理安排满足以上两个关系。

解题思路:
将每个点拆分成两种状态:留下和不留下,然后根据题目,设:A为队长,B和C为队员,那么就有!A->(B^C), (!Bv!C)->A, 然后每个关系中,有:B->!C, C->!B. 最终根据关系建边,判断矛盾关系是否在同一个连通分量内即可。
2-SAT类型的题,重要的就在于把这些对象间的关系理清楚。

个人感受:
这题充分考验了ACMer的语文水平,唉唉唉。

具体代码如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define ll long long
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 6e3 + 111;

vector<int> G[MAXN];
int n, m;
int dfn[MAXN], low[MAXN], sta[MAXN], id[MAXN], indx, scc, top;
bool in[MAXN];

void init() {
    for (int i = 0; i <= 6 * n; ++i) {
        G[i].clear();
        in[i] = 0;
        dfn[i] = 0;
    }
    indx = scc = top = 0;
}

void tarjan(int u) {
    dfn[u] = low[u] = ++indx;
    sta[top++] = u;
    in[u] = 1;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (in[v]) low[u] = min(low[u], dfn[v]);
    }

    if (dfn[u] == low[u]) {
        ++scc;
        int v;
        do {
            v = sta[--top];
            in[v] = 0;
            id[v] = scc;
        } while (v != u);
    }
}

int main()
{
    int a, b, c;
    while (~scanf("%d%d", &n, &m)) {
        init();
        int add = 3 * n;
        for (int i = 0; i < n; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            G[a + add].push_back(c);
            G[a + add].push_back(b);
            G[b + add].push_back(a);
            G[c + add].push_back(a);
        }
        int u, v;
        while (m --) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v + add);
            G[v].push_back(u + add);
        }

        for (int i = 0; i < 6 * n; ++i) {
            if (!dfn[i]) tarjan(i);
        }

        bool flag = 1;
        for (int i = 0; i < 3 * n; ++i) {
            if (id[i] == id[i + 3 * n]) {
                flag = 0;
                break;
            }
        }
        printf("%s\n", flag? "yes" : "no");
    }
    return 0;
}


广告时间

Java学习网站: how2j

VPS: VPS