poj2749 Building roads
题意是说有 N 个牛栏,现在通过一条通道(s1,s2)把他们连起来,他们之间有一些约束关系,一些牛栏不能连在同一个点,一些牛栏必须连在同一个点,现在问有没有可能把他们都连好,而且满足所有的约束关系,如果可以,输出两个牛栏之间距离最大值的最小情况。
比如牛栏 A 连在 s1 点,牛栏 B 连在 s2 点,那么AB之间的距离为(As1 + s1s2 + s2B);也可以两个牛栏连在同一个点上,比如 A 连在 s1 ,B 也连在 s1 ,那么AB的距离是(As1 + Bs1)。
A 表示连在s1,A‘ 表示连在 s2 ,按照给出的约束关系建边,然后在区间内2分枚举所有可能的解 ans,如果当前解满足条件,那么就意味着 ans 还可以更小,如果不满足,说明当前的 ans 值过大。
#include<iostream> #include<cstdio> #include<cstring> #include<stack> #include<cmath> #include<climits> #define find_min(a,b) (a<b?a:b) #define find_max(a,b) (a>b?a:b) using namespace std; const int N = 2010; struct point{ int x,y; }; point p[N]; struct Edge{ int s,e,next; }edge[5*N]; int n,e_num,vis_num,cnt,head[N],instack[N],low[N],tim[N],belong[N]; void AddEdge(int a,int b){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].next=head[a]; head[a]=e_num++; } int dis_m(point a,point b){ return abs(a.x-b.x)+abs(a.y-b.y); } stack <int>st; void tarjan(int x){ int i; tim[x]=low[x]=++vis_num; instack[x]=1; st.push(x); for(i=head[x];i!=-1;i=edge[i].next){ int u=edge[i].e; if(tim[u]==-1){ tarjan(u); if(low[x]>low[u])low[x]=low[u]; } else if(instack[u] && low[x]>tim[u])low[x]=tim[u]; } if(low[x]==tim[x]){ cnt++; do{ i=st.top(); st.pop(); instack[i]=0; belong[i]=cnt; }while(i!=x); } } void init(){ vis_num=cnt=0; memset(instack,0,sizeof(instack)); memset(belong,-1,sizeof(belong)); memset(tim,-1,sizeof(tim)); memset(low,0,sizeof(low)); } int main() { int A,B; int i,j,left,right,mid,ans; int hate[N][2],like[N][2]; point s1,s2; while(~scanf("%d%d%d",&n,&A,&B)) { scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y); int len=dis_m(s1,s2); int min=INT_MAX; int max=INT_MIN; for(i=0;i<n;i++){ scanf("%d%d",&p[i].x,&p[i].y); min=find_min(min, find_min(dis_m(p[i],s1),dis_m(p[i],s2)) ); max=find_max(max, find_max(dis_m(p[i],s1),dis_m(p[i],s2)) ); } for(i=0;i<A;i++){ scanf("%d%d",&hate[i][0],&hate[i][1]); hate[i][0]--; hate[i][1]--; } for(i=0;i<B;i++){ scanf("%d%d",&like[i][0],&like[i][1]); like[i][0]--; like[i][1]--; } left=2*min; right=2*max+len; ans=INT_MAX; while(left<=right){ e_num=0; memset(head,-1,sizeof(head)); for(i=0;i<A;i++){ AddEdge(2*hate[i][0],2*hate[i][1]+1); AddEdge(2*hate[i][0]+1,2*hate[i][1]); AddEdge(2*hate[i][1],2*hate[i][0]+1); AddEdge(2*hate[i][1]+1,2*hate[i][0]); } for(i=0;i<B;i++){ AddEdge(2*like[i][0],2*like[i][1]); AddEdge(2*like[i][0]+1,2*like[i][1]+1); AddEdge(2*like[i][1],2*like[i][0]); AddEdge(2*like[i][1]+1,2*like[i][0]+1); } mid=(left+right)/2; for(i=0;i<n;i++){ for(j=i+1;j<n;j++){ if(i!=j){ if(dis_m(p[i],s1)+dis_m(p[j],s1)>mid){ //点 i 到 s1 的距离加上点 j 到 s1 的距离大于所枚举的最大值,所以矛盾 AddEdge(2*i,2*j+1); AddEdge(2*j,2*i+1); } if(dis_m(p[i],s2)+dis_m(p[j],s2)>mid){ AddEdge(2*i+1,2*j); AddEdge(2*j+1,2*i); } if(dis_m(p[i],s1)+dis_m(p[j],s2)+len>mid){ AddEdge(2*i,2*j); AddEdge(2*j+1,2*i+1); } if(dis_m(p[j],s1)+dis_m(p[i],s2)+len>mid){ AddEdge(2*j,2*i); AddEdge(2*i+1,2*j+1); } } } } init(); for(i=0;i<2*n;i++){ if(tim[i]==-1)tarjan(i); } int flag=1; for(i=0;i<n;i++){ if(belong[2*i]==belong[2*i+1]){ flag=0;break; } } if(flag){ ans=find_min(mid,ans); right=mid-1; } else left=mid+1; } printf("%d\n",ans<INT_MAX?ans:-1); } return 0; }