POJ 2749 Building roads (2-sat)

本文介绍了一种解决特定图论问题的算法,该问题旨在找到连接多个点到线段两端时,任意两点间的最长距离最小化的方案。文章通过构建图模型,并使用Tarjan算法进行连通性分析来实现这一目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有一条线段,和n个点,把n个点连接在线段的端点处。。有a对点要连接在同一个点上,有b对点要连接在不同的点上。要使任意两点的最长距离最短。求最短距离

思路:假设有2*n个点,i点表示连接在start端,i+n表示连接在end端,则连接同一点的点对 i , j 有:i->j   j->i  i+n->j+n    j+n->i+n  

连在不同一点的点对:i,j 有: i->j+n    j->i+n      j+n->i      i+n->j     

距离的限制在注释里有。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
const int N = 2009;
const int M = 2009;
const int INF  = 0x3f3f3f3f;
int n,a,b;
struct cpoint{
    int x,y;
    void get(){scanf("%d%d",&x,&y);}
}star,end,re[N];
struct edge{
    int l,r;
    void get(){scanf("%d%d",&l,&r);}
} e1[M],e2[M];
int dist(cpoint &a,cpoint &b){
    //cout<<((a.x>b.x?a.x-b.x:b.x-a.x)+(a.y>b.y?a.y-b.y:b.y-a.y))<<endl;
    return (a.x>b.x?a.x-b.x:b.x-a.x)+(a.y>b.y?a.y-b.y:b.y-a.y);
}
stack<int> S;
bool post[N];
int dfn[N],low[N],col[N],color,ind;
struct LT{
    int to,nex;
} L[1000009];
int F[N],cnt;
void add(int f,int t)
{
    //cout<<f<<" "<<t<<endl;
    L[cnt].nex = F[f];
    L[cnt].to = t;
    F[f] = cnt++;
}
void tdfs(int k,int fa)
{
    //cout<<k<<" "<<fa<<endl;
    dfn[k] = low[k]=ind++;
    post[k]=1;S.push(k);
    for(int i=F[k];i;i=L[i].nex)
    {
        int to = L[i].to;
      //  if(to==fa) continue;
        if(!dfn[to])
        {
            tdfs(to,k);
            low[k] = min(low[to],low[k]);
        }
        else if(post[to]&&dfn[to]<low[k])
        {
            low[k] =dfn[to];
        }
    }
    if(low[k]==dfn[k])
    {
        int i;color++;
        for(i=S.top(),S.pop();i!=k;i=S.top(),S.pop())
        {
            post[i]=0;col[i] = color;
        }
        post[k]=0,col[k]=color;
    }
}
bool tarjan()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(col,0,sizeof(col));
    ind = 1,color=0;
    for(int i=1;i<=(n<<1);i++)
    if(!dfn[i]) tdfs(i,-1);
    for(int i=1;i<=n;i++)
    if(col[i]==col[i+n]) return false;
    return true;
}
int main()
{
    freopen("in.txt","r",stdin);
    scanf("%d%d%d",&n,&a,&b);
    star.get();end.get();
    for(int i=1;i<=n;i++) re[i].get();
    for(int i=1;i<=a;i++) e1[i].get();
    for(int i=1;i<=b;i++) e2[i].get();
    int ans = INF;
    int l=0,r=INF,mid;
    //cout<<INF<<endl;
    while(l<=r)
    {
        mid=(l+r)>>1;
        memset(F,0,sizeof(F));cnt=1;
        for(int i=1;i<=a;i++)
            add(e1[i].l,e1[i].r+n),add(e1[i].l+n,e1[i].r),
                add(e1[i].r,e1[i].l+n),add(e1[i].r+n,e1[i].l);
        for(int i=1;i<=b;i++)
            add(e2[i].l,e2[i].r),add(e2[i].l+n,e2[i].r+n),
                add(e2[i].r,e2[i].l),add(e2[i].r+n,e2[i].l+n);
        for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(dist(re[i],star)+dist(re[j],star)>mid)
            add(i,j+n),add(j,i+n);/// i在star 则 j不能在star,同理。。
            if(dist(re[i],end)+dist(re[j],end)>mid)
            add(i+n,j),add(j+n,i);/// i在end 则 j不能在end,同理。。
            if(dist(re[i],star)+dist(end,re[j])>mid-dist(star,end))
            add(i,j),add(j+n,i+n);/// i在star 则 j不能在end ,同理。。
            if(dist(re[i],end)+dist(star,re[j])>mid-dist(star,end))
            add(i+n,j+n),add(j,i);/// i在end 则 j不能在star ,同理。。
        }
        if(!tarjan())
        l=mid+1;//,cout<<l<<" "<<r<<endl;
        else ans=mid,r=mid-1;
    }
    printf("%d\n",ans==INF?-1:ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值