poj 2749 看的题解...

#include<iostream>
#include<vector>
#include<cmath>
#include<cstdlib>
#define N 1003
#include<cstring>
#include<cstdio>
using namespace std;
int n_barn, n_hate, n_friend; int len;
int stack[2*N]; int low[2*N]; int dfn[2*N]; bool in_stack[2*N]; int scc[2*N];
int color,index,top;
int done;
int n;
struct Point
{
    int x,y;
};

Point cor1,cor2;
int dist[2*N];
vector <int>  gt[2*N];
vector<int> g[2*N];
void init(int  max_dist);
void tarjan(int s);
 int get_dist(Point &p,Point &q);
 void solve();
 int  b_search();
 int check();
int main()
{
    freopen("in.txt","r",stdin);
    int x,y;
    Point point;
    while(cin>>n_barn>>n_hate>>n_friend){
    cin>>cor1.x>>cor1.y>>cor2.x>>cor2.y;
    len=get_dist(cor1,cor2);
    n=2*n_barn;
    for(int i=0;i<2*N;i++) gt[i].clear();
    for(int i=0;i<n_barn;i++)
    {
        scanf("%d%d",&point.x,&point.y);
        dist[2*i]=get_dist(point,cor1);
        dist[2*i+1]=get_dist(point,cor2);
    }
    for(int i=0;i<n_hate;i++)
    {
         scanf("%d%d",&x,&y);
         x-=1; y-=1;
         gt[2*x].push_back(2*y+1);
         gt[2*x+1].push_back(2*y);
         gt[2*y].push_back(2*x+1);
         gt[2*y+1].push_back(2*x);
    }
    for(int i=0;i<n_friend;i++)
    {
        scanf("%d%d",&x,&y);
        x-=1; y-=1;
        gt[2*x].push_back(2*y);
        gt[2*y].push_back(2*x);
        gt[2*x+1].push_back(2*y+1);
        gt[2*y+1].push_back(2*x+1);
    }


           x=b_search();
           if(done)
         cout<<x<<endl;
         else cout<<-1<<endl;
    }



}


void init(int  max_dist)
{

     for(int i=0;i<n;i++)
           g[i]=gt[i];
      for(int i=0;i<n_barn;i++)
        for(int j=i+1;j<n_barn;j++)
        {
            if(dist[2*i]+dist[2*j]>max_dist)
            {
                g[2*i].push_back(2*j+1);
                g[2*j].push_back(2*i+1);
            }
            if(dist[2*i]+dist[2*j+1]+len>max_dist)
            {
                g[2*i].push_back(2*j);
                g[2*j+1].push_back(2*i+1);
            }
            if(dist[2*i+1]+dist[2*j]+len>max_dist)
            {
                g[2*i+1].push_back(2*j+1);
                g[2*j].push_back(2*i);
            }
            if(dist[2*i+1]+dist[2*j+1]>max_dist)
            {
                g[2*i+1].push_back(2*j);
                g[2*j+1].push_back(2*i);
            }
        }
}



void tarjan(int s)
{
     low[s]=dfn[s]=++index;
     stack[top++]=s;
     in_stack[s]=true;
     vector <int> :: iterator p;
     for(p=g[s].begin();p!=g[s].end();p++)
     {
         if(!dfn[*p])
          {tarjan(*p);
          low[s]=min(low[s],low[*p]);
          }
        else if(in_stack[*p])  // 必须是在栈内
        {
            low[s]=min(low[s],dfn[*p]);
        }
     }
    if(dfn[s]==low[s])
    {
        color++;
        int t;
        do{
          t=stack[top-1];
          scc[t]=color;
          top--;
          in_stack[t]=false;
        }while(t!=s);
    }
 }

 void solve()
 {
     memset(in_stack,0,sizeof(in_stack));
     memset(dfn,0,sizeof(dfn));
     memset(low,0,sizeof(low));
     index=0; top=0; color=0;
     for(int i=0;i<2*n;i++)
       if(!dfn[i])
          tarjan(i);
 }

 int check()
 {
     for(int i=0;i<2*n;i+=2)
     {
         if(scc[i]==scc[i+1])
         return 0;
     }
     return 1;
 }

 int get_dist(Point &p,Point &q)
 {
      return    abs(p.x-q.x)+abs(p.y-q.y);
 }


int  b_search()
{
    done=0;
    int l=0;int r=5000000;
    int mid;
    while(l<r)
    {
        mid=(l+r)/2;
        init(mid);
        solve();
        if(!check())
        l=mid+1;
        else {r=mid; done=1;}
    }
    return l;
}


开始题意理解错了 以为求路径总和最短,

 

题目描述: 有n个牛棚,两个中转点M1,M2,牛棚只能连到中转点, 

而且有些牛棚只能连到相同的中转点,有些牛棚只能连在  不同的中转点;

要求最后使得牛棚之间最长距离 最小。

关于最大最小之类的,都是二分答案  多学习··· 

 对于x  y讨厌的关系:加边x->~y,  y->~x, ~x -> y, ~y->x 

   对于x  y喜欢的关系:加边x ->y, y->x  ~x->~y, ~y->~x 

另外,对于二分的最长路 mid:    如果直接相连的两点 d[i]+d[j] > mid,

表示必须连到不同中转点,加边i->~j, j->~i 

 如果两点连到不同中转点d[i]+d[j]+D>mid, 表示必须连到相同点,加边i->j, j->i

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值