poj 2749 看的题解...

来源:互联网 发布:人口学特征 知乎 编辑:程序博客网 时间:2024/06/06 11:45
#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

原创粉丝点击