POJ 2749 Building roads 【经典2-SAT+二分枚举】


传送门:POJ 2749


Building roads
Time Limit: 2000MS Memory Limit: 65536K

Problem Description
Farmer John’s farm has N barns, and there are some cows that live in each barn. The cows like to drop around, so John wants to build some roads to connect these barns. If he builds 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, though that’s the best choice for the cows.
Clever John just had another good idea. He first builds two transferring point S1 and S2, and then builds a road connecting S1 and S2 and N roads connecting each barn with S1 or S2, namely every barn will connect with S1 or S2, but not both. So that every pair of barns will be connected by the roads. To make the cows don’t spend too much time while dropping around, John wants to minimize the maximum of distances between every pair of barns.
That’s not the whole story because there is another troublesome problem. The cows of some barns hate each other, and John can’t connect their barns to the same transferring point. The cows of some barns are friends with each other, and John must connect their barns to the same transferring point. What a headache! Now John turns to you for help. Your task is to find a feasible optimal road-building scheme to make the maximum of distances between every pair of barns as short as possible, which means that you must decide which transferring point each barn should connect to.
We have known the coordinates of S1, S2 and the N barns, the pairs of barns in which the cows hate each other, and the pairs of barns in which the cows are friends with each other.
Note that John always builds roads vertically and horizontally, so the length of road between two places is their Manhattan distance. For example, saying two points with coordinates (x1, y1) and (x2, y2), the Manhattan distance between them 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, the number of pairs of barns in which the cows hate each other and the number of pairs of barns in which the cows are friends with each other.
Next line contains 4 integer sx1, sy1, sx2, sy2, which are the coordinates of two different transferring point S1 and S2 respectively.
Each of the following N line contains two integer x and y. They are coordinates of 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 hate each 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 are friends 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 the maximum of the distances between every pair of barns, if John selects the optimal road-building scheme. Note if there is no feasible solution, just output -1.

Sample Input
4 1 1
12750 28546 15361 32055
6706 3887
10754 8166
12668 19380
15788 16059
3 4
2 3

Sample Output
53246



题意:

John有n个牛棚,每个牛棚都住着一些牛,John想要建几条路把他们连接起来。他选择的方法是建两个相连中转站s1,s2。然后每个牛棚连接其中一个中转站就好啦。
现在的问题是有一些牛相互憎恨,所以不能连同一个中转站,而又有一些牛相互喜欢,必须连同一个中转站,现在要你来建边,要求,任意两个牛棚的距离的最大距离最短。

两点距离是指哈密顿距离。比如i, j连的是同一个中转站s1,距离就是dis(i,s1)+dis(j,s1) 如果连不同的中转站就是dis(i,s1)+dis(j,s2)+dis(s1,s2),这题目也不说清楚,弄了半天出不来答案。。。。


题解:

二分来枚举最大值,厌恶关系和喜欢关系是选择的约束条件,还有就是判断仓库和中转点之间的约束条件,假设i,j两个仓库和哪个中转点相连,用上面的距离计算公式计算距离,距离不能大于当前假设的最大距离mid,如果大于了那么就要约束他们不能这样连。



AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=1100;
int n,a,b,top;
bool mark[2*N];
int stack[2*N];
vector<int> g[2*N];
struct Node
{
  int x,y;
}barn[2*N],hate[2*N],like[2*N];
void init()
{
  memset(mark,false,sizeof(mark));
  for(int i=0;i<2*N;i++)
    g[i].clear();
}
int dis(Node a,Node b)//计算曼哈顿距离
{
  return abs(a.x-b.x)+abs(a.y-b.y);
}
void AddEdge(int x,int y)
{
  g[x].push_back(y);
}
bool dfs(int x)
{
  if(mark[x^1]) return false;
  if(mark[x]) return true;
  mark[x]=true;
  stack[++top]=x;
  int len=g[x].size();
  for(int i=0;i<len;i++)
  {
    if(!dfs(g[x][i])) return false;
  }
  return true;
}
bool twosat()
{
  for(int i=0;i<2*n;i+=2)
  {
    if(!mark[i]&&!mark[i+1])
    {
      top=0;
      if(!dfs(i))
      {
        while(top>0)
          mark[stack[top--]]=false;
        if(!dfs(i+1)) return false;
      }
    }
  }
  return true;
}
int main()
{
  int sx1,sy1,sx2,sy2;
  while(scanf("%d%d%d",&n,&a,&b)!=EOF)
  {
    int minn=inf,maxn=0;
    init();
    Node s1,s2;
    scanf("%d%d%d%d",&sx1,&sy1,&sx2,&sy2);
    s1.x=sx1;s1.y=sy1;s2.x=sx2;s2.y=sy2;
    for(int i=0;i<n;i++)
    {
      scanf("%d%d",&barn[i].x,&barn[i].y);
      minn=min(minn,min(dis(barn[i],s1),dis(barn[i],s2)));//计算单个点的最小距离
      maxn=max(maxn,max(dis(barn[i],s1),dis(barn[i],s2)));//计算单个点的最大距离
    }
    for(int i=0;i<a;i++)//输入互相厌倦的谷仓序号
    {
      scanf("%d%d",&hate[i].x,&hate[i].y);
      hate[i].x--;hate[i].y--;
    }
    for(int i=0;i<b;i++)//输入互相喜欢的谷仓序号
    {
      scanf("%d%d",&like[i].x,&like[i].y);
      like[i].x--;like[i].y--;
    }
    int l=2*minn,r=2*maxn+dis(s1,s2),ans=inf;
    while(l<=r)
    {
      init();
      int mid=(l+r)/2;//假设的最大距离
      for(int i=0;i<a;i++)//互相厌倦的不能连接同一个点
      {
        AddEdge(2*hate[i].x,2*hate[i].y+1);
        AddEdge(2*hate[i].x+1,2*hate[i].y);
        AddEdge(2*hate[i].y,2*hate[i].x+1);
        AddEdge(2*hate[i].y+1,2*hate[i].x);
      }
      for(int i=0;i<b;i++)//互相喜欢的必须连同一个点
      {
        AddEdge(2*like[i].x,2*like[i].y);
        AddEdge(2*like[i].x+1,2*like[i].y+1);
        AddEdge(2*like[i].y,2*like[i].x);
        AddEdge(2*like[i].y+1,2*like[i].x+1);
      }
      for(int i=0;i<n;i++)//遍历每两个点
      {
        for(int j=i+1;j<n;j++)
        {
          if(i==j) continue;
          if(dis(barn[i],s1)+dis(barn[j],s1)>mid)//如果i,j两点都连s1的距离大于假设的最大距离mid,则他们不能连同一个点
          {
            AddEdge(2*i,2*j+1);
            AddEdge(2*j,2*i+1);
          }
          if(dis(barn[i],s2)+dis(barn[j],s2)>mid)//如果i,j都连s2的距离大于mid,则他们不能都连s2
          {
            AddEdge(2*i+1,2*j);
            AddEdge(2*j+1,2*i);
          }
          if(dis(barn[i],s1)+dis(s1,s2)+dis(barn[j],s2)>mid)//如果i连s1,j连s2的距离大于mid
          {
            AddEdge(2*i,2*j);
            AddEdge(2*j+1,2*i+1);
          }
          if(dis(barn[i],s2)+dis(s1,s2)+dis(barn[j],s1)>mid)//如果i连s2,j连s1的距离大于mid
          {
            AddEdge(2*i+1,2*j+1);
            AddEdge(2*j,2*i);
          }
        }
      }
      if(twosat())//如果可行
      {
        ans=min(ans,mid);//计算最小的最大值
        r=mid-1;//往小的找
      }
      else//如果不可行,说明最小最大值在mid右边
        l=mid+1;
    }
    printf("%d\n",ans<inf?ans:-1);//判断是否可行
  }
  return 0;
}


相似题目:HDU 3622

HDU 3622题解

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值