题解NOI2017游戏

Posted Twilight_Sx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解NOI2017游戏相关的知识,希望对你有一定的参考价值。

2-SAT。洛谷P3845

一开始以为——怎么有3个呢?后来发现因为每个地图都有一种车是不能用的,所以就等于每一个地图都有两个适应的车啦。

那么对于x类型的地图呢——只有8个,直接2^8暴力枚举每一种可能,就转化为了普通的问题。

令u,u‘分别为一个地图适应的两种车,那么对于一个要求h1 - d1, h2 - d2而言,如果第一个既不是u,也不是u’,说明可以无视;如果第二个都不能满足,

就连d1 - d1‘,表示如果必须选第一辆,问题无解。其余情况则d1-d2,d2‘-d1‘(重要!保证图的对偶性)

#include <bits/stdc++.h>
using namespace std;
#define maxn 500050
int n, timer, dep[maxn], m, cnp = 1, d1[maxn], d2[maxn], c1[maxn], c2[maxn], cnt, a[maxn];
int low[maxn], dfn[maxn], num[maxn]; 
int sum;
int head[maxn]; 
bool flag = false, vis[maxn], mark[maxn];
string s; 
char tem1[3], tem2[3];
stack <int> st;

struct edge
{
    int last, to;
}E[maxn];

void add(int u, int v)
{ 
    E[cnp].to = v, E[cnp].last = head[u]; head[u] = cnp ++;
}

int getid(int r, int col)
{
    if(a[r] == col) return 0;
    else if(a[r] == 0) return 2 * r + col - 1;
    else if(a[r] == 1) return 2 * r + col / 2;
    else return 2 * r + col; 
}

void tarjan(int u)
{
    dep[u] = dfn[u] = low[u] = ++ timer;
    vis[u] = mark[u] = true;
    st.push(u);
    for(int i = head[u]; i; i = E[i].last)
    {
        int v = E[i].to;
        if(vis[v])
        { if(mark[v] && low[u] > dfn[v]) low[u] = dfn[v]; }
        else 
        {
            tarjan(v);
            low[u] = min(low[v], low[u]);
        }
    }
    if(dfn[u] == low[u])
    {
        int j;
        ++ cnt;
        do
        {
            j = st.top();
            st.pop();
            num[j] = cnt;
            mark[j] = false;
        }while(!st.empty() && j != u);
    }
}

void init()
{
    memset(head, 0, sizeof(head));
    memset(dep, 0, sizeof(dep));
    cnt = timer = 0, cnp = 1; 
    memset(vis, 0, sizeof(vis));
}

void solve()
{
    init();
    for(int i = 1; i <= m; i ++)
    {
        int x = getid(d1[i], c1[i]), y = getid(d2[i], c2[i]);
        if(x)
        {
            if(y) add(x, y), add(y ^ 1, x ^ 1);
            else add(x, x ^ 1);
        }
    }
    for(int i = 2; i <= 2 * n + 1; i ++)
        if(!vis[i]) tarjan(i);
    for(int i = 1; i <= n; i ++) 
        if(num[i * 2] == num[i * 2 ^ 1]) return;
    flag = true;
    for(int i = 1; i <= n; i ++)
    {
        if(a[i] == 0) putchar(num[i * 2] < num[i * 2 ^ 1] ? B : C);
        else if(a[i] == 1) putchar(num[i * 2] < num[i * 2 ^ 1] ? A : C);
        else putchar(num[i * 2] < num[i * 2 ^ 1] ? A : B);
    }
    return;
}

void dfs(int x)
{
    if(flag) return;
    if(x > n) 
    {
        solve();
        return;
    }
    if(a[x] == -1) a[x] = 0, dfs(x + 1), a[x] = 1;
    dfs(x + 1);
}

int main()
{
    string s;
    int d;
    cin >> n >> d;
    cin >> s;
    n = s.length();
    for(int i = 0; i < n; i ++)
    {
        if(s[i] == a) a[i + 1] = 0;
        else if(s[i] == b) a[i + 1] = 1;
        else if(s[i] == c) a[i + 1] = 2;
        else a[i + 1] = -1;
    }
    cin >> m;
    for(int i = 1; i <= m; i ++)
    {
        scanf("%d%s%d%s", &d1[i], tem1, &d2[i], tem2);
        c1[i] = tem1[0] - A, c2[i] = tem2[0] - A; 
    } 
    dfs(1);
    if(!flag) printf("-1\n");
    return 0;
}

 

以上是关于题解NOI2017游戏的主要内容,如果未能解决你的问题,请参考以下文章

NOI2017游戏 2-sat算法

BZOJ4945[Noi2017]游戏 2-SAT

[bzoj4945][Noi2017]游戏

洛谷3825 [NOI2017]游戏 2-sat

uoj#317[NOI2017]游戏 2-SAT

[NOI2017]游戏