poj 2749 Building roads

来源:互联网 发布:720 全景 h5 源码 编辑:程序博客网 时间:2024/06/06 02:35

题意:

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;elsel = mid;}printf( "%d\n", r );}else printf( "-1\n" );}return 0;}






原创粉丝点击