二分+2SAT njust1928 puzzle

传送门:点击打开链接

题意:小明在玩一个闯关游戏,共n关,必须按顺序通过,每一关会遇到两个数字(可能一样),他要选择其中一个,如果要选的这个数字是他之前选过的就直接过了这关。
但是他如果在某一关选了数字X,那就不能在经过另一关时选择数字Y当X+Y=2*n-1时,如果在某一关没有数可选的时候游戏结束,问在闯关游戏中小明最多可以通过几关。

思路:2SAT。。每一层,选第1个数字标记为0,选第2个数字标记为1,然后二分答案,建图跑2SAT就行了

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 1e4 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;

struct Edge {
    int v, nxt;
} E[MX];
int Head[MX][2], erear;
void edge_init() {
    erear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int z, int u, int v) {
    E[erear].v = v;
    E[erear].nxt = Head[u][z];
    Head[u][z] = erear++;
}
void edge_add(int u, int v) {
    edge_add(0, u, v);
    edge_add(1, v, u);
}
int Stack[MX], Belong[MX], vis[MX], ssz, bsz;
void DFS(int u, int s) {
    vis[u] = 1;
    if(s) Belong[u] = s;
    for(int i = Head[u][s > 0]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(!vis[v]) DFS(v, s);
    }
    if(!s) Stack[++ssz] = u;
}
void tarjan(int n) {
    ssz = bsz = 0;
    for(int i = 1; i <= n; i++) vis[i] = 0;
    for(int i = 1; i <= n; i++) {
        if(!vis[i]) DFS(i, 0);
    }
    for(int i = 1; i <= n; i++) vis[i] = 0;
    for(int i = ssz; i >= 1; i--) {
        if(!vis[Stack[i]]) DFS(Stack[i], ++bsz);
    }
}

int n, A[MX], B[MX];
vector<PII> S[MX];
bool check(int x) {
    edge_init();
    for(int i = 1; i <= 2 * n; i++) S[i].clear();
    for(int i = 1; i <= x; i++) {
        for(int k = 0; k <= 1; k++) {
            int w = 2 * n + 1 - (k ? B[i] : A[i]);
            for(int j = 0; j < S[w].size(); j++) {
                PII t = S[w][j];
                int v = t.first, id = t.second;
                edge_add(i + (k ? n : 0), v + (id ? 0 : n));
                edge_add(v + (id ? n : 0), i + (k ? 0 : n));
            }
        }
        S[A[i]].push_back(PII(i, 0));
        S[B[i]].push_back(PII(i, 1));
    }
    tarjan(2 * n);
    for(int i = 1; i <= n; i++) {
        if(Belong[i] == Belong[i + n]) return false;
    }
    return true;
}
int solve() {
    int l = 1, r = n, m;
    while(l <= r) {
        m = (l + r) >> 1;
        if(check(m)) l = m + 1;
        else r = m - 1;
    }
    return l - 1;
}
int main() {
    int T; //FIN;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &A[i], &B[i]);
            A[i]++; B[i]++;
        }
        printf("%d\n", solve());
    }
    return 0;
}


你可能感兴趣的:(二分+2SAT njust1928 puzzle)