0
点赞
收藏
分享

微信扫一扫

LightOJ - 1251 Forming the Council(2-SAT)


题目大意:N张票,M个人,每张票的形式如下
土i 土j,如果是+,表示要求留下,如果是-,表示要求离开
问能否满足每张票的其中一个要求,如果可以,输出多少个人留下,并按升序输出留下的人

解题思路:2-SAT的模版题,这里只是验证一下模版

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int MAXNODE = 10010 * 2;

struct TwoSat{
    int n, top;
    vector<int> G[MAXNODE];
    bool mark[MAXNODE];
    int Stack[MAXNODE];

    void init(int n) {
        this->n = n;
        for (int i = 0; i < 2 * n; i++)
            G[i].clear();
        memset(mark, 0, sizeof(mark));
    }

    //x = xval或者y = yval
    void AddClause(int x, int xval, int y, int yval) {
        x = x * 2 + xval;
        y = y * 2 + yval;
        G[x ^ 1].push_back(y);
        G[y ^ 1].push_back(x);
    }

    bool dfs(int u) {
        //当前需要标记的结点是u,如果u ^ 1这个结点已经被标记过了,就表示两个结点都要被标记掉,明显冲突了
        if (mark[u ^ 1]) return false;

        if (mark[u]) return true;
        mark[u] = true;
        //模拟栈
        Stack[++top] = u;
        //和u相邻的点都进行标记,以判断是否出错
        for (int i = 0; i < G[u].size(); i++) 
            if (!dfs(G[u][i])) return false;
        return true;
    }

    bool solve() {
        for (int i = 0; i < 2 * n; i += 2) 
            //如果在其他点的标志过程中,其中一个点被标记了,就无需在枚举了,因为在dfs的过程中,和其相连的点也被标记了,较少了重复枚举
            if (!mark[i] && !mark[i ^ 1]) {
                top = 0;
                //假设xi为假是错误的,这时候就要进行回溯,将dfs过程中标记过的点还原,再判断对错 
                if (!dfs(i)) {
                    while (top) mark[Stack[top--]] = false;
                    if (!dfs(i ^ 1)) return false;
                }
            }
        return true;
    }
}Two;

int n, m, cas = 1;
void solve() {
    scanf("%d%d", &n, &m);
    Two.init(m);

    char vote1[10], vote2[10];
    int x, xval, y, yval, len;

    for (int i = 0; i < n; i++) { 
        scanf("%s%s", vote1, vote2);
        len = strlen(vote1);

        if (vote1[0] == '+') xval = 0;
        else xval = 1;

        x = 0;
        for (int j = 1; j < len; j++) 
            x = x * 10 + vote1[j] - '0';

        len = strlen(vote2);
        if (vote2[0] == '+') yval = 0;
        else yval = 1;

        y = 0;
        for (int j = 1; j < len; j++)
            y = y * 10 + vote2[j] - '0';
        Two.AddClause(x - 1, xval, y - 1, yval);
    }
    if (!Two.solve()) 
        printf("Case %d: No\n", cas++);
    else {
        vector<int> members;
        int ans = 0;
        for (int i = 0; i < 2 * m; i += 2) {
            if (Two.mark[i]) {
                ans++;
                members.push_back(i / 2 + 1);
            }
        }
        if (ans == 0) printf("Case %d: Yes\n0\n", cas++);
        else {
            printf("Case %d: Yes\n", cas++);
            printf("%d", ans);
            for (int j = 0; j < members.size(); j++)
                printf(" %d", members[j]);
            printf("\n");
        }
    }
}

int main() {
    int test;
    scanf("%d", &test);
    while (test--) solve();
    return 0;
}


举报

相关推荐

0 条评论