njust1928 puzzle(2-sat)

来源:互联网 发布:人工智能在医疗领域 编辑:程序博客网 时间:2024/06/06 23:29

njust1928

题目

https://icpc.njust.edu.cn/Problem/Local/1928/

思路

“首先二分一下可以闯过的关卡数,然后2sat建模就好”
标程:https://icpc.njust.edu.cn/gist/comzyh/de84632a-2687-413a-b3ae-c6483e23fe7d/

吐槽:maxn开小了,边加错了,第一次写2-sat。

代码

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <queue>using namespace std;const int maxn=3000;struct node{    int u,v,c;} p[maxn];int dfn[maxn],low[maxn],next_[maxn],head[maxn],instack[maxn],belong[maxn];int cnt,ind,n,e;stack<int> st;int x[maxn],y[maxn];void addnode(int u,int v,int c){    node q;    q.u=u,q.v=v,q.c=c;    p[e]=q;    next_[e]=head[u];    head[u]=e++;}void init(){    for(int i=0; i<=maxn; i++)        head[i]=next_[i]=-1;    while(!st.empty()) st.pop();    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(instack,0,sizeof(maxn));    memset(belong,0,sizeof(belong));    cnt=0,e=0,ind=0;}void tarjan(int k){    dfn[k]=low[k]=++ind;    instack[k]=1;    st.push(k);    for(int i=head[k]; i!=-1; i=next_[i])    {        int v=p[i].v;        if(!dfn[v])        {            tarjan(v);            low[k]=min(low[k],low[v]);        }        else if(instack[v])        {            low[k]=min(low[k],dfn[v]);        }    }    if(dfn[k]==low[k])    {        int v;        cnt++;        do        {            v=st.top();            st.pop();            instack[v]=0;            belong[v]=cnt;        }        while(v!=k);    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i=0; i<n; i++)        {            int a,b;            scanf("%d %d",&a,&b);            x[i]=a,y[i]=b;        }        int left=0,right=n;        while(left<=right)        {            int mid=(left+right) >>1;            init();            for(int i=0; i<mid; i++)            {                addnode(2*n-1-y[i],x[i],1);                addnode(2*n-1-x[i],y[i],1);            }            int flag=1;            for(int i=0; i<2*n; i++)                if(!dfn[i])                    tarjan(i);            for(int i=0; i<mid; i++)                if(belong[i]==belong[2*n-1-i])                {                    flag=0;                    break;                }            if(!flag) right=mid-1;            else left=mid+1;        }        printf("%d\n",(right+left)/2);    }    return 0;}
0 0