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

poj 2749 Building roads

2013-05-09 16:25 316 查看
题意:

N 头牛要转移到2个聚集地,但是存在一些矛盾关系:

1. 有 A 组牛相互敌视,所以不能将他们聚集到一个聚集地。 2. 有 B 组牛相互友好,所以他们一定要聚集在一个聚集地

聚集地和每头牛初始时都有位置(x, y ),每头牛走到聚集地需要修路(起点为牛的位置,终点为聚集地,路距为 the Manhattan distance |x1 - x2| + |y1 - y2|),二个聚集点之间一定有条路,现在要求你求出在有解的情况下,建边(修路)将图根据不同的可行的方式连通,使得一个图的最大的两头牛距离最小,要求输出这个最小距离。

分析:

首先我很快想到了,矛盾(敌视和友好关系)可以根据 2-sat 来求解,但是求最短距离我有些模糊,在分析测试数据时,我根据与题意有差异的方式也得到了答案,结果让我走了弯路,白写了 100 行左右的代码(很悲催呀),理解题意后,我用暴力事了一下,很简单,能过测试数据,但思路明显有问题的(在 WA 了以后),好吧,搜报告了。。。

求最大距离的最短值,需要用二分。一开始我死也想不通,后来,根据报告里的简图方式我理解了,用一个距离来限制,以得出矛盾关系,然后 2-sat 求解,如有解,则缩小距离限制,否则加大距离限制:(最大可能的距离有 4 中情况,某一点到 s1 与某一点到 s2 为相反情况)

dist( u -> s1 ) + dist( v -> s1 )  > limit
 u -> !v , v -> !u

dist( u -> s2 ) + dist( v -> s2 )  > limit
 !u -> v , !v -> u

dist( u -> s1 ) + dist( v -> s2 ) + dist( s1 -> s2 )  > limit     u -> v, !v -> !u;

dist( u -> s2 ) + dist( v -> s1 ) + dist( s1 -> s2 )  > limit      !u -> !v, v -> u;

另外

敌视的矛盾关系建边:A xor B = 1

友好的矛盾关系建边:A xor B = 0

这道题目用 vector 的效率会比邻接表慢一些,其中距离的最大值限制为4000000,这可以作为二分的 inf 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 11000;
const int inf = 4000000;
vector<int>edge[maxn];
int n, N, A, B, U[maxn], V[maxn];
int tmpdfn, dfn[maxn], low[maxn], inst[maxn], belong[maxn], st[maxn], top, scnt;
struct PP{
int x, y;
}pos[maxn];
int dd( int x ){ if( x < 0 )return -x; return x; }
int dist( PP a, PP b ){ return dd( a.x - b.x ) + dd( a.y - b.y ); }
void tarjan( int u )
{
int i, v, t, size;
low[u] = dfn[u] = tmpdfn++;
st[top++] = u;
inst[u] = 1;
size = edge[u].size();
for( i = 0; i < size; i++ )
{
v = edge[u][i];
if( dfn[v] == -1 )
{
tarjan( v );
low[u] = min( low[u], low[v] );
}
else if( inst[v] )low[u] = min( low[u], dfn[v] );
}
if( dfn[u] == low[u] )
{
do{ belong[t = st[--top]] = scnt; inst[t] = 0; }while( t != u );
scnt++;
}
}
bool SCC()
{
int i;
top = 0;
tmpdfn = scnt = 1;
memset( dfn, -1, sizeof(dfn) );
memset( inst, 0, sizeof(inst) );
for( i = 1; i <= n * 2; i++ )if( dfn[i] == -1 )tarjan( i );
for( i = 1; i <= n; i++ )if( belong[i] == belong[i + n] )return false;
return true;
}
void build( int limit )
{
int i, j, u, v;
for( i = 1; i <= n * 2; i++ )edge[i].clear();
for( i = 1; i <= A; i++ )
{
u = U[i]; v = V[i];
edge[u].push_back( v + n );
edge[v].push_back( u + n );
edge[v + n].push_back( u );
edge[u + n].push_back( v );
}
for( i = 1; i <= B; i++ )
{
u = U[i + A]; v = V[i + A];
edge[u].push_back( v );
edge[v].push_back( u );
edge[u + n].push_back( v + n );
edge[v + n].push_back( u + n );
}
for( i = 1; i <= n; i++ )
{
for( j = i + 1; j <= n; j++ )
{
if( dist( pos[N + 1], pos[i] ) + dist( pos[N + 1], pos[j] ) > limit )
{
edge[i].push_back( j + n );
edge[j].push_back( i + n );
}
if( dist( pos[N + 2], pos[i] ) + dist( pos[N + 2], pos[j] ) > limit )
{
edge[i + n].push_back( j );
edge[j + n].push_back( i );
}
if( dist( pos[N + 1], pos[i] ) + dist( pos[N + 2], pos[j] ) + dist( pos[N + 1], pos[N + 2] ) > limit )
{
edge[i].push_back( j );
edge[j + n].push_back( i + n );
}
if( dist( pos[N + 2], pos[i] ) + dist( pos[N + 1], pos[j] ) + dist( pos[N + 1], pos[N + 2] ) > limit )
{
edge[j].push_back( i );
edge[i + n].push_back( j + n );
}
}
}
}
int main()
{
int i, j, u, v, num;
while( ~scanf( "%d%d%d", &N, &A, &B ) )
{
n = N;
for( i = 1; i <= n * 2; i++ )edge[i].clear();
scanf( "%d%d%d%d", &pos[N + 1].x, &pos[N + 1].y, &pos[N + 2].x, &pos[N + 2].y );
for( i = 1; i <= N; i++ )scanf( "%d%d", &pos[i].x, &pos[i].y );
for( j = 1; j <= A; j++ )
{
scanf( "%d%d", &U[j], &V[j] );
u = U[j]; v = V[j];
edge[u].push_back( v + n );
edge[v].push_back( u + n );
edge[v + n].push_back( u );
edge[u + n].push_back( v );
}
for( j = 1; j <= B; j++ )
{
scanf( "%d%d", &U[j + A], &V[j + A] );
u = U[j + A]; v = V[j + A];
edge[u].push_back( v );
edge[v].push_back( u );
edge[u + n].push_back( v + n );
edge[v + n].push_back( u + n );
}
if( SCC() )
{
int l, r, mid;
l = 0; r = inf;
while( l + 1 != r )
{
mid = l + ( r - l ) / 2;
build( mid );
if( SCC() )
r = mid;
else
l = mid;
}
printf( "%d\n", r );
}
else
printf( "-1\n" );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分查找 POJ