UVA 1391 2-SAT

UVA 1391

题目链接:

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=38529

题意:

n个人,年龄在均值以下的去AC,以上去BC

m中仇恨方式,问一种合理的方案并输出。

思路:

2-SAT

我没有看题解哦

我没有看题解哦

我没有看题解哦

我没有看题解哦~

刚开始想怎么去处理三种状态,然后按照之前打版的方法打了一发连样例都没有过。

然后把加边的地方lin[u^1].push_back(v)改成lin[u].push_back(v^1)。居然过样例了。嗯WA了。

想了想是不是因为对于每个点属于A或者B的情况、即取他为TRUE的情况都没有点接在后面,每次dfs就直接赋值为TRUE。试着翻转了一下每个点为TRUE的状态,即设0FALSE1TRUEWA

玩了两分钟手机,决定从原理上想一想。

2-SAT的原理是数理逻辑。假设AB真,则A假时B一定真,B假时A一定真,然而AB真的情况也是存在的。但本题存在AB真都不合法的情况,就是AB的年龄都在一个年龄段上时。

关键代码:

            if(age[u/2] == age[v/2]){

                lin[u].push_back(v^1);

                lin[v].push_back(u^1);

            }

然后就A了,WA了四发吧,可以去打省赛了。

 

源码:

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <stack>

#include <queue>

#include <vector>

using namespace std;

const int MAXN = 100000 + 5;

vector<int>lin[MAXN * 2];

stack<int>sta;

int n, m;

int age[MAXN];

int valid[MAXN * 2];

double ave;

bool dfs(int u)

{

    if(valid[u^1])  return false;

    if(valid[u])    return true;

    valid[u] = 1;

    sta.push(u);

    for(int i = 0 ; i < (int)lin[u].size() ; i++){

        int v = lin[u][i];

        if(!dfs(v)) return false;

    }

    return true;

}

bool solve()

{

    while(!sta.empty()) sta.pop();

    memset(valid, 0, sizeof(valid));

    for(int i = 0 ; i < 2 * n ; i+=2){

        if(!valid[i] && !valid[i^1]){

            if(!dfs(i)){

                while(!sta.empty()){

                    int org = sta.top();    sta.pop();

                    valid[org] = 0;

                    if(org == i)    break;

                }

                if(!dfs(i^1))   return false;

            }

        }

    }

    return true;

}

int main()

{

    while(scanf("%d%d", &n, &m) != EOF && n + m){

        ave = 0;

        for(int i = 0 ; i < n ; i++)

            scanf("%d", &age[i]), ave += age[i];

        for(int i = 0 ; i < 2 * n ; i++)

            lin[i].clear();

        ave /= (1.0 * n);

        for(int i = 0 ; i < n ; i++){

            if(age[i] >= ave)   age[i] = 0;

            else    age[i] = 1;

        }

        int u, v;

        for(int i = 1 ; i <= m ; i++){

            scanf("%d%d", &u, &v);

            u--, v--;

            u *= 2, v *= 2;

            lin[u^1].push_back(v);

            lin[v^1].push_back(u);

            if(age[u/2] == age[v/2]){

                lin[u].push_back(v^1);

                lin[v].push_back(u^1);

            }

        }

//        for(int i = 0 ; i < 2 * n ; i++){

//            printf("lin[%d] = ", i) ;

//            for(int j = 0 ; j < (int)lin[i].size() ; j++)

//                printf("%d ", lin[i][j]);

//            printf("\n");

//        }

        if(solve()){

            for(int i = 0 ; i < 2 * n ; i += 2){

                if(valid[i]){

                    if(!age[i / 2])    printf("A\n");

                    else    printf("B\n");

                }

                else    printf("C\n");

            }

        }

        else

            printf("No solution\n");

    }

    return 0;

}

/*

16 20

21

22

23

24

25

26

27

28

101

102

103

104

105

106

107

108

1 2

3 4

5 6

7 8

9 10

11 12

13 14

15 16

1 10

2 9

3 12

4 11

5 14

6 13

7 16

8 15

1 12

1 13

3 16

6 15

0 0

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值