UVALive - 4452 The Ministers' Major Mess(2-SAT)

题目大意:有n个人对m个方案投票,每个人最多只能对其中的4个方案投票(其他的相当于弃权),每一票要么支持要么反对。问是否存在一个最终决定,使得每个投票人都有超过一半的建议被采纳,在所有可能的最终决定中,哪些方案的态度是确定的

解题思路:参考了一下别人的思路,学习了

当想要确定某一个状态(i)时,可以用他的相反状态(i^1)和该状态建立一条边,那样的话,每当dfs到他的相反状态时,就会return false

在理解了上面的基础上,就可以建边了

首先,要有超过一半的投票被采纳。也就是说,当投票数小于等于2的时候,每一票都要被采纳,当投票数大于2时,只能有一票被否定,依此建边

接着就是判断能否被采纳了,可以枚举每个方案的最终决定,如果有一个方案无论是被否定还是被肯定都是错的话,那么就不可能满足所有人的要求了(超过一半的建议被采纳),可以在枚举的时候边记录最终状态的态度

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define N 110
#define M 1010

struct vote{
    int bill, vote;
}V[M][5];
vector<int> G[M];

int ans[N];
int n, m;
bool mark[N * 2];

void AddEdge(int x, int valx, int y, int valy) {
    x = x * 2 + valx;
    y = y * 2 + valy;
    G[x].push_back(y);
}

void init() {

    for (int i = 0; i < 2 * n; i++)
        G[i].clear();

    int t;
    char c;
    for (int i = 0; i < m; i++) {
        scanf("%d", &t);
        for (int j = 0; j < t; j++) {
            scanf("%d %c", &V[i][j].bill, &c);
            V[i][j].bill--;
            if (c == ‘y‘)
                V[i][j].vote = 1;
            else
                V[i][j].vote = 0;
        }

        if (t <= 2) {
            for (int j = 0; j < t; j++)
                AddEdge(V[i][j].bill, V[i][j].vote ^ 1, V[i][j].bill, V[i][j].vote);
        }
        else {
            for (int j = 0; j < t; j++)
                for (int k = 0; k < t; k++) {
                    if (j == k)
                        continue;
                    AddEdge(V[i][j].bill, V[i][j].vote ^ 1, V[i][k].bill, V[i][k].vote);
                }
        }
    }
}

int S[M];
int c;

bool dfs(int u) {
    if (mark[u ^ 1])
        return false;
    if (mark[u])
        return true;
    mark[u] = true;
    S[++c] = u;
    for (int i = 0; i < G[u].size(); i++)
        if (!dfs(G[u][i]))
            return false;
    return true;
}

bool TwoAST() {
    for (int i = 0; i < 2 * n; i += 2) {
        if (!mark[i] && !mark[i ^ 1]) {
            c = 0;
            if (!dfs(i)) {
                while (c)
                    mark[S[c--]] = false;
                if (!dfs(i ^ 1))
                    return false;
            }
        }
    }
    return true;
}

int cas = 1;
void solve() {
    int i;
    for (i = 0; i < n; i++) {
        int tmp = 0;
        memset(mark, 0, sizeof(mark));
        //第i个方案被否定时
        AddEdge(i, 1, i, 0);

        if (TwoAST())
            tmp += 1;
        G[(i << 1) ^ 1].pop_back();

        //第i个方案被肯定时
        memset(mark, 0, sizeof(mark));
        AddEdge(i, 0, i, 1);

        if (TwoAST())
            tmp += 2;
        G[(i << 1)].pop_back();
        if (tmp == 0)
            break;
        else if(tmp == 1)
            ans[i] = 0;
        else if (tmp == 2)
            ans[i] = 1;
        else if (tmp == 3)
            ans[i] = 2;
    }

    printf("Case %d: ", cas++);
    if (i != n) {
        printf("impossible\n");
        return ;
    }

    for (int i = 0; i < n; i++) {
        if (!ans[i])
            printf("n");
        else if(ans[i] == 1)
            printf("y");
        else if(ans[i] == 2)
            printf("?");
    }
    printf("\n");
}

int main() {
    while (scanf("%d%d", &n, &m) != EOF && n + m) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

UVALive - 4452 The Ministers' Major Mess(2-SAT)

时间: 2024-10-11 01:24:30

UVALive - 4452 The Ministers' Major Mess(2-SAT)的相关文章

UVA 1086 - The Ministers&#39; Major Mess(2-sat)

UVA 1086 - The Ministers' Major Mess 题目链接 题意:有n个方案,每个人投票,一个人最多投4张票,现在要有一个方案,使得满足所有人投票方案中有超过一半被满足,输出方案的对错,如果一个方案对错都可以,就输出? 思路:明显是二分图,一开始想错了,想从正着去把条件式化简,根本不可行 正确的做法是,反过来想,因为最多4张票并且超过1半,如果反过来想选哪些方案不满足,那么就只有1和0的情况,就很容易构造表达式了,然后就是2-sat,对于?的情况,只要遍历一遍,每个位置再

UVALive-4452 The Ministers&#39; Major Mess (2-SAT)

题目大意:有n个问题,m个人来投票,没人最多投4票,问该怎样决定才能使每个人都有超过一半的票数被认可? 题目分析:2-SAT问题.如果某个人投的票数少于2,则这两票军被采纳,如果票数至少三票,则最多有一票可以不被采纳,这意味着这个人的投的任意两票之间有矛盾,是“二者取一”的关系. 代码如下: # include<iostream> # include<cstdio> # include<vector> # include<queue> # include&l

Flipped

More praise for FLIPPED "We flipped over this fantastic book, its gutsy girl Juli and its wise, wonderful ending." --The Chicago Tribune "Delightful! Delicious! And totally teen." --BookPage * "With a charismatic leading lady kids

UVALive - 3211 (2-SAT + 二分)

layout: post title: 训练指南 UVALive - 3211 (2-SAT + 二分) author: "luowentaoaa" catalog: true mathjax: true tags: - 2-SAT - 图论 - 训练指南 Now or later UVALive - 3211 题意 n架飞机,每架可选择两个着落时间.安排一个着陆时间表,使得着陆间隔的最小值最大 题解 二分查找最大值P,每次都用2-SAT判断是否可行. #include<bits

异常:Unsupported major.minor version 52.0 (Use --stacktrace to see the full trace)

异常:Unsupported major.minor version 52.0 (Use --stacktrace to see the full trace) 正在写一个功能,更新了同事提交的代码之后,出现了如下错误: 1 Fatal error during compilation org.apache.tools.ant.BuildException: java.lang.UnsupportedClassVersionError: org/elasticsearch/index/query

UVALive 4848 Tour Belt

F - Tour Belt Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4848 Description Korea has many tourist attractions. One of them is an archipelago (Dadohae in Korean), a cluster of small islands sca

UVALive 6467 Strahler Order 拓扑排序

这题是今天下午BNU SUMMER TRAINING的C题 是队友给的解题思路,用拓扑排序然后就可以了 最后是3A 其中两次RE竟然是因为: scanf("%d",mm); ORZ 以后能用CIN还是CIN吧 QAQ 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostre

LA 3211 飞机调度(2—SAT)

https://vjudge.net/problem/UVALive-3211 题意: 有n架飞机需要着陆,每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种,第i架飞机的早着陆时间为E,晚着陆时间为L,不得在其他时间着陆.你的任务是为这些飞机安排着陆方式,使得整个着陆计划尽量安全.换句话说,如果把所有飞机的实际着陆时间按照从早到晚的顺序排列,相邻两个着陆时间间隔的最小值. 思路: 二分查找最大值P,每次都用2—SAT判断是否可行. 1 #include<iostream>

UVALive 7077 Little Zu Chongzhi&#39;s Triangles (有序序列和三角形的关系)

这个题……我上来就给读错了,我以为最后是一个三角形,一条边可以由多个小棒组成,所以想到了状态压缩各种各样的东西,最后成功了……结果发现样例过不了,三条黑线就在我的脑袋上挂着,改正了以后我发现N非常小,想到了回溯每个棍的分组,最多分5组,结果发现超时了……最大是5^12 =  244,140,625,厉害呢…… 后来想贪心,首先想暴力出所有可能的组合,结果发现替换问题是一个难题……最后T T ,我就断片了.. 等看了别人的办法以后,我才发现我忽视了三角形的特性,和把数据排序以后的特点. 如果数据从