procedure2012
It's not worth it to know you're not worth it!

[关键字]:2-sat

[题目大意]:把n个数由s1、s2两个点连接,有些店不能连在同一个点上,有些点必须连在同一个点上,问罪大边最小为多少,无解输出-1

//=====================================================================================================

[分析]:其实一部分很好想到:A为连在s1A’为连在s2,由此可构建2-sat图。但是我在这里犯了个错误:因该连A->B'\A'->B\B->A'\B'->A(只是以不能在同一个点的情况为例),我却只连了A->B'\B->A'。另一分可以很快想到二分答案但关键是如何判断,我想了半天还是没想出来,其实是枚举每两个点,如果它们都连在s1、s2上超了二分的答案,就把它们归为不可连在同一个点上,如果它们分别连在s1和s2上超了二分的答案,就把它们归为必须连在一个点上,然后和刚才一样的连边,用2-sat缩点判断是否成立。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 5000
#define INF 1000000000

struct rec
{
int x,y;
}s1,s2,p[MAXN];
int n,a,b,sum,tot,Min,Max,len;
int dfn[MAXN],low[MAXN],belong[MAXN];
int hate[MAXN][2],like[MAXN][2];
bool instack[MAXN];
vector<int> e[MAXN];

int dis(rec a,rec b)
{
return abs(a.x-b.x)+abs(a.y-b.y);
}

stack<int> s;
void tarjan(int u)
{
dfn[u]=low[u]=++tot;
s.push(u);
instack[u]=1;
int i,size=e[u].size();
for (i=0;i<size;i++)
{
int v=e[u][i];
if (!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
if (instack[v]) low[u]=min(low[u],dfn[v]);
}
if (dfn[u]==low[u])
{
sum++;
do{
i=s.top();
s.pop();
instack[i]=0;
belong[i]=sum;
}while (i!=u);
}
}

bool solved()
{
sum=tot=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(instack,0,sizeof(instack));
memset(belong,0,sizeof(belong));
for (int i=0;i<n*2;i++)
if (!dfn[i]) tarjan(i);
for (int i=0;i<2*n;i+=2)
if (belong[i]==belong[i+1]) return 0;
return 1;
}

bool solve(int mid)
{
for (int i=0;i<2*n;i++) e[i].clear();
for (int i=0;i<a;i++)
{
int x=hate[i][0],y=hate[i][1];
e[x*2].push_back(y*2+1);
e[x*2+1].push_back(y*2);
e[y*2].push_back(x*2+1);
e[y*2+1].push_back(x*2);
}
for (int i=0;i<b;i++)
{
int x=like[i][0],y=like[i][1];
e[x*2].push_back(y*2);
e[x*2+1].push_back(y*2+1);
e[y*2].push_back(x*2);
e[y*2+1].push_back(x*2+1);
}
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
if (i!=j)
{
if (dis(p[i],s1)+dis(p[j],s1)>mid)
e[i*2].push_back(j*2+1),e[j*2].push_back(i*2+1);
if (dis(p[i],s2)+dis(p[j],s2)>mid)
e[i*2+1].push_back(j*2),e[j*2+1].push_back(i*2);
if (dis(p[i],s1)+dis(p[j],s2)+len>mid)
e[i*2].push_back(j*2),e[j*2+1].push_back(i*2+1);
if (dis(p[j],s1)+dis(p[i],s2)+len>mid)
e[j*2].push_back(i*2),e[i*2+1].push_back(j*2+1);
}
return solved();
}

int main()
{
scanf("%d%d%d",&n,&a,&b);
scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y);
len=dis(s1,s2);
Min=INF,Max=0;
for (int i=0;i<n;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
Min=min(min(dis(p[i],s1),dis(p[i],s2)),Min);
Max=max(max(dis(p[i],s1),dis(p[i],s2)),Max);
}
for (int i=0;i<a;i++)
{
scanf("%d%d",&hate[i][0],&hate[i][1]);
hate[i][0]--,hate[i][1]--;
}
for (int i=0;i<b;i++)
{
scanf("%d%d",&like[i][0],&like[i][1]);
like[i][0]--,like[i][1]--;
}
//==============================================================================
int l=Min*2,r=Max*2+len,mid,ans=INF;
while (l<=r)
{
mid=(l+r)/2;
if (solve(mid)) r=mid-1,ans=mid; else l=mid+1;
}
//==============================================================================
printf("%d\n",ans==INF?-1:ans);
system("pause");
return 0;
}



posted on 2012-02-11 00:02  procedure2012  阅读(264)  评论(0编辑  收藏  举报