您的位置:首页 > 产品设计 > UI/UE

HDOJ 1815 Building roads(2-sat简介)

2017-06-03 12:28 267 查看
2-sat问题又称稳定党员问题,下面将对2-sat问题进行简要的概述

问题引入:一共有2n个人,分成n个帮派,每个帮派两个人,有一天这些帮派要进行一个重要会议,要求每个帮派只能派出一个人来参加会议,每个帮派之间还有相对矛盾的条件,比如帮派A中的一个人与帮派B中的某一个人不能同时参加会议,问满足这种条件的前提下是否能够有n个人参加会议。

问题分析:同一个帮派的两个人不能同时参加会议。那么我们就是要处理相对矛盾的关系。

设(a0,a1)为一个帮派,设(b0,b1)是另一个帮派。

如果存在a0——b0这样的矛盾关系,那么在选择的时候,如果在帮派1中选a0,那么就必须在帮派2中选b1,可以建有向边(a0,b1),如果在帮派2中选b0,那么就必须在帮派1中选a1,可以建有向边(b0,a1)。

对所有约束条件建好边后,可以知道我们已经处理好了第二种约束条件,接下来要处理的就是第一个约束条件,同一帮派中的两个人只能有且只有一个人参加会议,具体实现方法就是判断是否存在类似于我选了a0推到必须选a1,那么就可以想到可以用Tarjan找强连通分量,缩点染色,判断同一帮派中的人是否在同一强连通分量种即可,若在,则说明无解,否则有解。

附上一道题目(不过这道题的难度比入门题略高)

Building roads
TimeLimit: 10000/1000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)

Total Submission(s): 1459    Accepted Submission(s): 450


Problem Description

Farmer John'sfarm has N barns, and there are some cows that live in each barn. The cows liketo drop around, so John wants to build some roads to connect these barns. If hebuilds roads for every pair of different barns, then he must build N * (N - 1)/ 2 roads,
which is so costly that cheapskate John will never do that, thoughthat's the best choice for the cows.

Clever John just had another good idea. He first builds two transferring pointS1 and S2, and then builds a road connecting S1 and S2 and N roads connectingeach barn with S1 or S2, namely every barn will connect with S1 or S2, but notboth. So that every pair
of barns will be connected by the roads. To make thecows don't spend too much time while dropping around, John wants to minimizethe maximum of distances between every pair of barns.

That's not the whole story because there is another troublesome problem. Thecows of some barns hate each other, and John can't connect their barns to thesame transferring point. The cows of some barns are friends with each other,and John must connect their
barns to the same transferring point. What aheadache! Now John turns to you for help. Your task is to find a feasibleoptimal road-building scheme to make the maximum of distances between everypair of barns as short as possible, which means that you must decide
whichtransferring point each barn should connect to.

We have known the coordinates of S1, S2 and the N barns, the pairs of barns inwhich the cows hate each other, and the pairs of barns in which the cows arefriends with each other.

Note that John always builds roads vertically and horizontally, so the lengthof road between two places is their Manhattan distance. For example, saying twopoints with coordinates (x1, y1) and (x2, y2), the Manhattan distance betweenthem is |x1 - x2| + |y1
- y2|.

 
 
Input

The first line of input consists of 3 integers N, A and B (2 <= N <= 500, 0<= A <= 1000, 0 <= B <= 1000), which are the number of barns, thenumber of pairs of barns in which the cows hate each other and the number ofpairs of barns in which the cows are friends
with each other.

Next line contains 4 integer sx1, sy1, sx2, sy2, which are the coordinates oftwo different transferring point S1 and S2 respectively.

Each of the following N line contains two integer x and y. They are coordinatesof the barns from the first barn to the last one.

Each of the following A lines contains two different integers i and j(1 <= i< j <= N), which represent the i-th and j-th barns in which the cows hateeach other.

The same pair of barns never appears more than once.

Each of the following B lines contains two different integers i and j(1 <= i< j <= N), which represent the i-th and j-th barns in which the cows arefriends with each other. The same pair of barns never appears more than once.

You should note that all the coordinates are in the range [-1000000, 1000000].

 
 
Output

You just need output a line containing a single integer, which represents themaximum of the distances between every pair of barns, if John selects theoptimal road-building scheme. Note if there is no feasible solution, justoutput -1.

 
 
Sample Input

4 1 1

12750 28546 1536132055

6706 3887

10754 8166

12668 19380

15788 16059

3 4

2 3

 
 
Sample Output

53246

题意

给出n个农场和两个中转站s1,2,每个农场都必须连接一个中转站,且只能连一个,给出所有点的坐标,对应距离为曼哈顿距离(|xi-xj|+|yi-yj|),求如何建图能够使得其中所有点距离的最大值最小化。其中s1和s2之间有一条已有的路。

给出a个限制条件,这a个限制条件中的两个农场不能连接同一个中转站

给出b个限制条件,这b个限制条件中的两个农场必须连接同一个中转站

思路:首先对于最小化最大值类似的问题,我们很容易想到用二分答案的方法。

对应每个农场,要么连接s1,要么连接s2,那么对应建点:1~n表示点选择连接s1,n+1~2n表示点选择连接s2。

对于农场x,用x表示连接s1,用!x表示连接s2

(1)两个农场不能连接同一个中转站,建边(a, !b),(b, !a),(!b, a),(!a, b)

(2)两个农场必须连接同一个中转站,建边(a,  b),(b,  a),(!b, !a),(!a,! b)

对于二分出来的当前mid值,对应还有约束条件,找到矛盾边,然后继续建图

(1)对应两个点,如果其距离大于了mid,那么这个值不
4000
满足,直接退出。

(2)点i选择s1,点j选择s1    if(dis1[i]+dis1[j]>mid)      建边(i,! j),(j, ! i)                                     i ,j 不能同时选择s1

(3)点i选择s1,点j选择s2    if(dis1[i]+dis2[j]+Dis1_2>mid)   建边(i, j),(! i, ! j)                       若i选择s1,则j不能选择s2;若j选择s2,i不能选择s1               

(4)点i选择s2,点j选择s2    if(dis2[i]+dis(2[j]>mid)     建边 (!i,j),(!j,i)                               i, j 不能同时选择s2

(5)点i选择s2,点j选择s1    if(dis2[i]+dis1[j]+Dis1_2>mid)   建边(!i,!j),(j,i)                     
若i选择s2,则j不能选择s1;若j选择s1,i不能选择s2   

然后就是用Tarjan找强连通分量,缩点染色,判断是否存在一个点既连接s1,又连接s2的情况

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 1050;
const int mod = 10007;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)

int head[maxn];
int low[maxn],dfn[maxn];
int vis[maxn];
int color[maxn];
int stack[maxn];
int dis1[maxn],dis2[maxn];
int n,a,b,Dis;
int tot,cnt,top,num;

struct node
{
int v,w,next;
} e[maxn*maxn];

struct point
{
int x,y;
} hate[maxn],like[maxn],mp[maxn],s1,s2;

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

void init()
{
tot=0;
cnt=1;
top=-1;
num=0;
mst(stack,0),mst(vis,0);
mst(low,0),mst(dfn,0);
mst(color,0),mst(head,-1);
}

void add(int u,int v)
{
e[tot].v=v;
//e[tot].w=w;
e[tot].next=head[u];
head[u]=tot++;
}

void tarjan(int now)
{
vis[now]=1;
low[now]=dfn[now]=cnt++;
stack[++top]=now;
for(int i=head[now]; ~i; i=e[i].next)
{
int v=e[i].v;
if(vis[v]==0)
tarjan(v);
if(vis[v]==1) low[now]=min(low[now],low[v]);
}
if(low[now]==dfn[now])
{
num++;
do
{
vis[stack[top]]=-1;
color[stack[top]]=num;
}
while(stack[top--]!=now);
}
}

int build(int x)
{
init();
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
{
if(getdis(mp[i],mp[j])>x)
return false;
}
for(int i=1; i<=a; i++)
{
int x=hate[i].x,y=hate[i].y;
add(x,y+n);
add(y,x+n);
add(y+n,x);
add(x+n,y);
}
for(int i=1; i<=b; i++)
{
int x=like[i].x,y=like[i].y;
add(x,y);
add(y,x);
add(y+n,x+n);
add(x+n,y+n);
}
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
{
if(dis1[i]+dis1[j]>x)
{
add(i,j+n);
add(j,i+n);
}
if(dis2[i]+dis2[j]>x)
{
add(i+n,j);
add(j+n,i);
}
if(dis1[i]+dis2[j]+Dis>x)
{
add(i,j);
add(j+n,i+n);
}
if(dis2[i]+dis1[j]+Dis>x)
{
add(i+n,j+n);
add(j,i);
}
}

return true;
}

bool judge(int x)
{
bool flag=build(x);
if(flag==0)
return false;
for(int i=1; i<=2*n; i++)
{
if(vis[i]==0)
tarjan(i);
}
for(int i=1; i<=n; i++)
{
if(color[i]==color[i+n])
return false;
}
return true;
}

void solve()
{
int l=0,r=INF;
int ans=-1;
while(l<=r)
{
int m=(l+r)/2;
if(judge(m))
{
r=m-1;
ans=m;
}
else l=m+1;
}
printf("%d\n",ans);
}

int main()
{
while(~scanf("%d%d%d",&n,&a,&b))
{
scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y);
Dis=getdis(s1,s2);
for(int i=1; i<=n; i++)
{
scanf("%d%d",&mp[i].x,&mp[i].y);
dis1[i]=getdis(mp[i],s1);
dis2[i]=getdis(mp[i],s2);
}
for(int i=1; i<=a; i++)
{
scanf("%d%d",&hate[i].x,&hate[i].y);
}
for(int i=1; i<=b; i++)
{
scanf("%d%d",&like[i].x,&like[i].y);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  强连通Tarjan 2-sat