【题解】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;
}

原文地址:https://www.cnblogs.com/twilight-sx/p/8445813.html

时间: 2024-11-09 00:40:54

【题解】NOI2017游戏的相关文章

【BZOJ4945】[Noi2017]游戏 2-SAT

[BZOJ4945][Noi2017]游戏 题目描述 题解:2-SAT学艺不精啊! 这题一打眼看上去是个3-SAT?哎?3-SAT不是NPC吗?哎?这题x怎么只有8个?暴力走起! 因为x要么不是A要么不是B,所以直接2^8枚举所有x就行了.然后就变成了一个2-SAT问题.假设有两场游戏1,2,分别可以使用的地图为A1,A2,B1,B2,如果有一个限制是1 A 2 A,那么选A1就必须选A2,然后我这个沙茶就开开心心的拿了55分. 为什么不对?我建出来的图显然不对偶啊!考虑逆否命题,选A1就必须选

[题解]Mayan游戏

Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1.每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见图6到图7):如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参

【uoj#317】[NOI2017]游戏 2-SAT

题目描述 给出 $n$ 个赛车赛道和A.B.C三种赛车,除了 $d$ 个赛道可以使用所有三种赛车以外每个都只能使用给出的两种之一.另外给出 $m$ 条限制:某个赛道使用X则某另一个赛道必须使用Y.问:是否存在一种方案满足所有条件?输出一种合法方案. $n]le 50000,d\le 8,m\le 100000$ . 题解 2-SAT 3-SAT是NP完全问题,由于 $d$ 只有 $8$ ,因此考虑枚举每个万能位置的取值,转化为2-SAT问题. 那么对于一条限制,显然描述对应着一条边:另外一个命题

[题解] [JSOI2013] 游戏中的学问

题面 题解 这个数据范围, 直接 DP 一下就完了 看是这个人新开一个圈还是加到别的圈里去 注意, 新开一个圈最少需要三个人 设 \(f[i][j]\) 为前 \(i\) 个人组成 \(j\) 个圈的方案数 \[ f[i][j] = \begin{cases} f[i - 1][j] * (i - 1)\f[i - 3][j - 1] * (i - 1) * (i - 2)\\end{cases} \] 没了 Code #include <algorithm> #include <ios

BZOJ4945 NOI2017 游戏 - 2-SAT

这题放在NOI里应该不算难的吧--但是细节比较多,所以写起来会有点** 题目限定了道路不能通行某种车辆,也就是可以通行两种车辆 我们将这两种车辆分别作为正点和反点进行约束就可以了 建图较为容易 最后将所有的x枚举一下即可 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #inclu

[NOI2017]游戏

Sol 然而我的代码在\(UOJ\)上被\(hack\)\(\ TLE\)了 但思路是没问题的\(TAT\) 如果没有\(x\),就是个\(2-SAT\) 我们爆搜\(x\)的地图是\(a\)还是\(b\)就好了 不用枚举它是\(c\),枚举\(a\),\(b\)就能保证正好选\(ABC\)三种车 我也不知道我的输出方案哪里学的 拓扑排序+染色\(QAQ\) 如果觉得自己的代码优秀就去\(UOJ\)上交吧(逃 # include <bits/stdc++.h> # define RG regi

loj2305 noi2017 游戏

题目链接 思路 既然\(x\)的数量那么小,我们就可以先把每个\(x\)搜索一遍. 枚举x的时候不需要把\(a,b,c\)全枚举一遍,只要枚举其中的两个就可以枚举到当前位置选任何车的情况. 然后就变成了只有\('a','b','c'\)的序列.寻找满足题目要求的方案. \(2-sat\)模型. 连边的时候注意一些技巧,否则\(if\)写到自闭.. 在\(UOJ\)上会被卡掉\(3\)分.实在懒得去卡常了233 代码 /* * @Author: wxyww * @Date: 2019-04-29

【题解】游戏

题目描述见Luogu P2462. 算法分析 其实这道题并不难,关键是如何转化.因为需要找到最长的单词接龙,就可以用图论来看.单词接龙不会出现环,所以,这就是个DAG上的拓扑排序.如果两个单词可以接在一起,就必须满足以下条件: 前一个单词的字母都必须在后一个单词中出现过 任意一个字母都不能少 后一个单词的长度比前一个单词多1,不能多也不能少 因为没有对顺序作要求,我们只需记录其出现次数即可,并存储它们的哈希值(hash/散列),枚举每个字符串的每个字母,增加其出现次数,并判断该字符串是否存在,如

Codeforces Round #263 (Div. 1) 题解

A:Appleman and Toastman 题意:两个人玩游戏 初始第一个人给第二个人一个数组 第二个人把数组中每个数相加的和加到他的总得分里面,然后把这个数组还给第一个人,第一个人进行操作:若数组中只剩下一个数,就把这个数组扔了,否则把这个数组拆成两个数组扔回给第二个人,求第二个人的最大得分. 题解:游戏结束即为数组中N个数全被拆成了单独的一个数,而且我们可以知道若一个数在第一个人操作第K次时候变成只有一个数的数组,那么这个数在第二个人那算了K+1次,于是不难想到贪心算法,即让越大的数算的