HDU 3715 Go Deeper 二分 + 2-sat

来源:互联网 发布:武侠之数据悍匪笔趣阁 编辑:程序博客网 时间:2024/05/29 21:33

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=3715

题意:

给定一段递归伪代码,问执行这段伪代码递归的最深层数

思路:

二分枚举答案用2-sat判定是否可行。具体建图如下:如果c[i] == 0,那么a[i] OR b[i],如果c[i] == 1,那么(a[i] AND b[i]) OR (~a[i] AND ~b[i]),如果c[i] == 2,那么NOT(a[i] AND b[i]),然后强连通缩点判断i和~i是否在同一个环内

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <cmath>using namespace std;const int N = 410;const double eps = 1e-8;struct edge{    int to, next;} g[N*N*2];int cnt, head[N], cnt1, head1[N];int dfn[N], low[N], scc[N], st[N], top, num, idx;int a[N*N], b[N*N], c[N*N];bool vis[N];int n, m;void add_edge(int v, int u){    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void init(){    memset(head, -1, sizeof head);    memset(dfn, -1, sizeof dfn);    memset(vis, 0, sizeof vis);    top = num = idx = cnt = 0;}void tarjan(int v){    dfn[v] = low[v] = ++idx;    vis[v] = true, st[top++] = v;    int u;    for(int i = head[v]; i != -1; i = g[i].next)    {        u = g[i].to;        if(dfn[u] == -1)        {            tarjan(u);            low[v] = min(low[v], low[u]);        }        else if(vis[u]) low[v] = min(low[v], dfn[u]);    }    if(dfn[v] == low[v])    {        num++;        do        {            u = st[--top];            vis[u] = false;            scc[u] = num;        }        while(u != v);    }}bool work(int mid){    init();    for(int i = 0; i < mid; i++)    {        if(c[i] == 0)        {            add_edge(a[i] + n, b[i]), add_edge(b[i] + n, a[i]);        }        else if(c[i] == 1)        {            add_edge(a[i], b[i]), add_edge(b[i], a[i]);            add_edge(a[i] + n, b[i] + n), add_edge(b[i] + n, a[i] + n);        }        else if(c[i] == 2)        {            add_edge(a[i], b[i] + n), add_edge(b[i], a[i] + n);        }    }    for(int i = 0; i < 2*n; i++)        if(dfn[i] == -1) tarjan(i);    for(int i = 0; i < n; i++)        if(scc[i] == scc[i+n]) return false;    return true;}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &n, &m);        for(int i = 0; i < m; i++) scanf("%d%d%d", &a[i], &b[i], &c[i]);        int l = 0, r = m, res;        while(l <= r)        {            int mid = (l + r) / 2;            if(work(mid)) l = mid + 1, res = mid;            else r = mid - 1;        }        printf("%d\n", res);    }    return 0;}
0 0