题意:给你两个中转点s1,s2,和很多其他的点d{},d{}里面的点只能连接s1或s2,不能同时连接两个,给你一些关系:com(a,b)表示a,b要同时连接同一个中转点,dex(a,b)表示a,b不能同时连接同一个中转点,问你d{}里面的两对点的最大距离的最小值。
想法:看到了最大距离的最小值,显然用二分枚举,这里有一个小优化,我们不容易确定最大的一个距离点对,但是我们可以很容易的找到一个最小的。
这道题就是考建图,分为两个方面:1.com和dex的建图。2.极限距离的限制建图
还有就是一个很重要的一点:建图的时候,你的建边顺序不正确,你的答案也可能超时,这是我的亲身经历,之前以为无所谓的。(但是我不知道为什么?会的留言)
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<stack> #define inf 0x7fffffff using namespace std; const int nd=1000+50; int N,A,B; struct node { int x,y; }Dian[500+5],s1,s2; int downlimit; int fuck[1100][2],sex[1100][2]; struct nodee { int v,next; }e[nd*nd*10]; int head[nd],cnt; int s_1[500+5],s_2[500+5]; int dfn[nd],low[nd],instack[nd],paint[nd],index,col; stack<int>s; void Init() { index=col=1; while(!s.empty()) s.pop(); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(paint,0,sizeof(paint)); memset(instack,0,sizeof(instack)); memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b) { e[cnt].v=b; e[cnt].next=head[a]; head[a]=cnt++; } int MIN(int a,int b) { if(a<b) return a; return b; } void tarjan(int u) { dfn[u]=low[u]=index++; instack[u]=1; s.push(u); for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(!dfn[v]) { tarjan(v); low[u]=MIN(low[u],low[v]); } else if(instack[v]) { low[u]=MIN(low[u],dfn[v]); } } if(dfn[u]==low[u]) { int k=s.top(); while(k!=u) { s.pop(); paint[k]=col; instack[k]=0; k=s.top(); } s.pop(); paint[u]=col; instack[u]=0; col++; } } int abss(int x) { if(x>0) return x; return -x; } inline int dis(node a,node b) { return abss(a.x-b.x)+abss(a.y-b.y); } void Input() { scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y); downlimit=inf; for(int i=1;i<=N;i++) { scanf("%d%d",&Dian[i].x,&Dian[i].y); s_1[i]=dis(Dian[i],s1);s_2[i]=dis(Dian[i],s2); if(downlimit>s_1[i]) downlimit=s_1[i]; if(downlimit>s_2[i]) downlimit=s_2[i]; } for(int i=1;i<=A;i++) { scanf("%d%d",&fuck[i][0],&fuck[i][1]); } for(int i=1;i<=B;i++) { scanf("%d%d",&sex[i][0],&sex[i][1]); } } bool judge(int limt) { Init(); for(int i=1;i<=A;i++) { int a=fuck[i][0],b=fuck[i][1]; add(a,b+N); add(b,a+N); add(b+N,a); add(a+N,b); } for(int i=1;i<=B;i++) { int a=sex[i][0],b=sex[i][1]; add(a,b); add(a+N,b+N); add(b,a); add(b+N,a+N); } int D=dis(s1,s2); for(int i=1;i<N;i++) { for(int j=i+1;j<=N;j++) { if(limt<s_1[i]+s_1[j]) {//不能都选是 add(i,j+N); add(j,i+N); } if(limt<s_2[i]+s_2[j]) {//不能都选否 add(i+N,j); add(j+N,i); } if(limt<s_1[i]+D+s_2[j]) {//不能同时i选是,j选否 add(i,j); add(j+N,i+N); } if(limt<s_1[j]+D+s_2[i]) {//不能同时i选否,j选是 add(i+N,j+N); add(j,i); } } } for(int i=1;i<=2*N;i++) { if(!dfn[i]) tarjan(i); } for(int i=1;i<=N;i++) { if(paint[i]==paint[i+N]) { return false; } } return true; } void treatment() { int low=downlimit,up=8000000; int ans=-1; while(low<=up) { int mid=(low+up)/2; if(judge(mid)) { ans=mid; up=mid-1; } else low=mid+1; } printf("%d\n",ans); } int main() { while(~scanf("%d%d%d",&N,&A,&B)) { Input(); treatment(); } return 0; }