zoukankan      html  css  js  c++  java
  • SPOJ 9939 Eliminate the Conflict

    SPOJ_9939

        这个题目可以用2-SAT做。

        首先既然是2-SAT的问题的话,我们就要去找核心变量,然而B的每局的选择却是3个,石头(1)、剪子(2)、布(3),难道3-SAT?开玩笑,目前至少我没见过3-SAT的题目。仔细想一下,其实选择也就两个,因为A的选择是定的,而我们必须让A赢,因此B的选择实际上只有两个。

        找到核心变量之后就是构图了,由于构图要稍复杂一些,就不直接用字母代替了,还是用一个实例来说明一下吧。

        我们不妨一共3局,A出的分别是1、2、3,那么我们可以得到B的选择如下。

        B1      1      2      1

        B2      2      3      3

        !B      3      1      2

        其中B1、B2为B的两个选择,!B为B所不能选的。

        现在假设M为2,分别为1 2 1、2 3 0,也就是说B的选择在第1局和第2局时必须不同,在第2局和第3局地选择必须相同。

        首先我们建1 2 1这个要求的边。假设第1局选1的话,那么第2局选什么都无所谓的,因此没有必然的关系,所以第1局的1就不用连边了。假设第1局选2的话,那么第2局就一定要选3,这样就需要连一条左边的2到右边的3的有向边。同理,右边的2到左边的1也需要连一条有向边。

        然后建2 3 0这个要求的边。假设第2局选2的话,就会发现第3局是选什么都不行的,因此第2局必然不能选2,因此我们需要连一条左边的2到左边的3的有向边,意思是如果第2局选了2那么第2局必然选3,这样在最后求可行解的时候就必然不会把2选入内,也就确保了第2局不会选2。假设第2局选3的话,那么显然第3局也必然选3,这样连一条左边的3到右边的3的有向边。同理,还需要连一条右边的1到右边的3的有向边,和一条右边的3到左边的3的有向边。

        其实所有的边都按上面说的原理去构造就可以了。建完图之后的任务就轻松了,只需要tarjan求强连通分量、缩点,然后判断一下就可以了。

    #include<stdio.h>
    #include<string.h>
    #define MAXD 20010
    #define MAXM 80010
    int e, first[MAXD], next[MAXM], v[MAXM], st[MAXD], A[MAXD];
    int dfn[MAXD], low[MAXD], color[MAXD], s[MAXD], top, cnt, col, ins[MAXD];
    int N, M;
    void add(int a, int b)
    {
    v[e] = b;
    next[e] = first[a];
    first[a] = e;
    e ++;
    }
    void init()
    {
    int i, j, a, b, k, x, y;
    scanf("%d%d", &N, &M);
    memset(first, -1, sizeof(first));
    e = 0;
    for(i = 0; i < N; i ++)
    {
    scanf("%d", &A[i]);
    if(A[i] == 1)
    {
    st[2 * i] = 1;
    st[2 * i ^ 1] = 2;
    A[i] = 3;
    }
    else if(A[i] == 2)
    {
    st[2 * i] = 2;
    st[2 * i ^ 1] = 3;
    A[i] = 1;
    }
    else
    {
    st[2 * i] = 1;
    st[2 * i ^ 1] = 3;
    A[i] = 2;
    }
    }
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d", &a, &b, &k);
    a --;
    b --;
    x = 2 * a;
    y = 2 * b;
    if(k)
    {
    if(st[x] != A[b])
    {
    if(st[x] == st[y])
    add(x, y ^ 1);
    else
    add(x, y);
    }
    if(st[x ^ 1] != A[b])
    {
    if(st[x ^ 1] == st[y])
    add(x ^ 1, y ^ 1);
    else
    add(x ^ 1, y);
    }
    if(st[y] != A[a])
    {
    if(st[y] == st[x])
    add(y, x ^ 1);
    else
    add(y, x);
    }
    if(st[y ^ 1] != A[a])
    {
    if(st[y ^ 1] == st[x])
    add(y ^ 1, x ^ 1);
    else
    add(y ^ 1, x);
    }
    }
    else
    {
    if(st[x] == A[b])
    add(x, x ^ 1);
    else
    {
    if(st[x] == st[y])
    add(x, y);
    else
    add(x, y ^ 1);
    }
    if(st[x ^ 1] == A[b])
    add(x ^ 1, x);
    else
    {
    if(st[x ^ 1] == st[y])
    add(x ^ 1, y);
    else
    add(x ^ 1, y ^ 1);
    }
    if(st[y] == A[a])
    add(y, y ^ 1);
    else
    {
    if(st[y] == st[x])
    add(y, x);
    else
    add(y, x ^ 1);
    }
    if(st[y ^ 1] == A[a])
    add(y ^ 1, y);
    else
    {
    if(st[y ^ 1] == st[x])
    add(y ^ 1, x);
    else
    add(y ^ 1, x ^ 1);
    }
    }
    }
    }
    void tarjan(int u)
    {
    int i;
    dfn[u] = low[u] = ++ cnt;
    s[top ++] = u;
    ins[u] = 1;
    for(i = first[u]; i != -1; i = next[i])
    {
    if(!dfn[v[i]])
    {
    tarjan(v[i]);
    if(low[v[i]] < low[u])
    low[u] = low[v[i]];
    }
    else if(ins[v[i]] && dfn[v[i]] < low[u])
    low[u] = dfn[v[i]];
    }
    if(low[u] == dfn[u])
    {
    for(s[top] = -1; s[top] != u;)
    {
    top --;
    ins[s[top]] = 0;
    color[s[top]] = col;
    }
    col ++;
    }
    }
    int judge()
    {
    int i;
    for(i = 0; i < N; i ++)
    if(color[2 * i] == color[2 * i ^ 1])
    return 0;
    return 1;
    }
    void solve()
    {
    int i, j, k;
    col = cnt = top = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(ins, 0, sizeof(ins));
    for(i = 0; i < 2 * N; i ++)
    if(!dfn[i])
    tarjan(i);
    if(judge())
    printf("yes\n");
    else
    printf("no\n");
    }
    int main()
    {
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
    init();
    printf("Case #%d: ", tt + 1);
    solve();
    }
    return 0;
    }
  • 相关阅读:
    [Android开发]cocos2dx工程中接入支付宝sdk
    cocos2dx android SDK接入总结
    Cocos2d-vs避免过长编译的小技巧
    math.h里的数学计算公式介绍
    Cocos Code IDE入门指南
    kbengine引擎的安装
    游戏服务端pomelo完整安装配置过程
    cocos2d-x 两个场景间进行传参数
    cocos2d-x 设置全局可变变量
    如何将cocos2d-x项目打包成一个.exe
  • 原文地址:https://www.cnblogs.com/staginner/p/2243569.html
Copyright © 2011-2022 走看看