[poj] 2749 building roads

原题

2-SAT+二分答案!
最小的最大值,这肯定是二分答案。而我们要2-SATcheck是否在该情况下有可行解。
对于目前的答案limit,首先把爱和恨连边,然后我们n^2枚举每两个点通过判断距离来实现连边,然后跑2-SAT判断是否有可行解
O(n^2logn)
想起来和听起来都很难写,事实上还好吧…

#include<cstdio>
#include<algorithm>
#include<stack>
#include<cstring>
#define inf 97797977
#define N 510
using namespace std;
int n,m,A,B,lovex[2*N],lovey[2*N],hatex[2*N],hatey[2*N],dis1[N],dis2[N],dis,sx1,sx2,sy1,sy2,x[N],y[N],head[2*N];
int bel[2*N],cnt=1,l,r=inf,dfn[2*N],low[2*N],t,mid,sum;
stack <int> stk;
bool instk[2*N];
struct hhh
{
    int to,next;
}edge[10*N*N];

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;(j<'0' || j>'9') && j!='-';j=getchar()) ;
    if (j=='-') j=getchar(),fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

void add(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

bool build()
{
    for (int i=1;i<=B;i++)
    {
	add(lovex[i],lovey[i]);
	add(lovey[i],lovex[i]);
	add(lovex[i]+n,lovey[i]+n);
	add(lovey[i]+n,lovex[i]+n);
    }
    for (int i=1;i<=A;i++)
    {
	add(hatex[i],hatey[i]+n);
	add(hatex[i]+n,hatey[i]);
	add(hatey[i]+n,hatex[i]);
	add(hatey[i],hatex[i]+n);
    }
    for (int i=1;i<=n;i++)
	for (int j=i+1;j<=n;j++)
	{
	    int t=0;
	    if (dis1[i]+dis+dis2[j]>mid)
	    {
		add(i,j);
		add(j+n,i+n);
		t++;
	    }
	    if (dis2[i]+dis+dis1[j]>mid)
	    {
		add(i+n,j+n);
		add(j,i);
		t++;
	    }
	    if (dis1[i]+dis1[j]>mid)
	    {
		add(i,j+n);
		add(j,i+n);
		t++;
	    }
	    if (dis2[i]+dis2[j]>mid)
	    {
		add(i+n,j);
		add(j+n,i);
		t++;
	    }
	    if (t==4) return 0;
	}
    return 1;
}

void Tarjan(int u)
{
    dfn[u]=low[u]=++t;
    stk.push(u);
    instk[u]=1;
    for (int i=head[u],v;i;i=edge[i].next)
    {
	v=edge[i].to;
	if (!dfn[v])
	{
	    Tarjan(v);
	    low[u]=min(low[u],low[v]);
	}
	else if (instk[v]) low[u]=min(low[u],dfn[v]);
    }
    if (low[u]==dfn[u])
    {
	sum++;
	int t;
	do
	{
	    t=stk.top();
	    bel[t]=sum;
	    stk.pop();
	    instk[t]=0;
	}while(t!=u);
    }
}

bool check()
{
    for (int i=1;i<=n;i++)
	if (bel[i]==bel[i+n]) return 0;
    return 1;
}

int get1(int i)
{
    return abs(sx1-x[i])+abs(sy1-y[i]);
}

int get2(int i)
{
    return abs(sx2-x[i])+abs(sy2-y[i]);
}

int main()
{
    n=read();
    A=read();
    B=read();
    sx1=read();
    sy1=read();
    sx2=read();
    sy2=read();
    dis=abs(sx1-sx2)+abs(sy1-sy2);
    for (int i=1;i<=n;i++)
    {
	x[i]=read();
	y[i]=read();
    }
    for (int i=1;i<=A;i++)
    {
	hatex[i]=read();
	hatey[i]=read();
    }
    for (int i=1;i<=B;i++)
    {
	lovex[i]=read();
	lovey[i]=read();
    }
    for (int i=1;i<=n;i++)
    {
	dis1[i]=get1(i);
	dis2[i]=get2(i);
    }
    while (l<r)
    {
	mid=(l+r)>>1;
	cnt=1;
	memset(dfn,0,sizeof(dfn));
	memset(bel,0,sizeof(bel));
	memset(head,0,sizeof(head));
	if (build())
	{
	    t=1;
	    sum=1;
	    for (int i=1;i<=2*n;i++)
		if (!dfn[i]) Tarjan(i);
	    if (check()) r=mid;
	    else l=mid+1;
	}
	else l=mid+1;
    }
    printf("%d",l>=inf?-1:l);
    return 0;
}

posted @ 2017-11-18 10:51  Mrha  阅读(141)  评论(0编辑  收藏  举报