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;
}