题解:
二分答案
先按照原有的条件建边,然后按照二分不能满足的条件建边
然后判断是否可行
代码:
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> const int N=2005; using namespace std; int n,m1,m2,num,flag,ans,tot,head[N],X[N],Y[N],dist1[N],dist2[N]; int scc[N],vis[N],stack1[N],x1,x2,x,y,y11,y2,stack2[N]; struct edge{int v,next;}g[N*N]; void init() { memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); memset(scc,0,sizeof(scc)); stack1[0]=stack2[0]=num=0; flag=1; } void jb(int u,int v) { num++; g[num].v=v; g[num].next=head[u]; head[u]=num; } int js(int x1,int y1,int x2,int y2){return abs(x1-x2)+abs(y1-y2);} void dfs(int cur,int &sig,int &cnt) { if (!flag)return; vis[cur]=++sig; stack1[++stack1[0]]=cur; stack2[++stack2[0]]=cur; for (int i=head[cur];i;i=g[i].next) if (!vis[g[i].v]) dfs(g[i].v,sig,cnt); else if (!scc[g[i].v]) while (vis[stack2[stack2[0]]]>vis[g[i].v])stack2[0]--; if (stack2[stack2[0]]==cur) { stack2[0]--; ++cnt; do { scc[stack1[stack1[0]]]=cnt; int tmp=stack1[stack1[0]]; if ((tmp>=n&&scc[tmp-n]==cnt)||(tmp<n&&scc[tmp+n]==cnt)) { flag=0; return; } } while (stack1[stack1[0]--]!=cur); } } void solve() { int l=0,r=4000000; ans=-1; while (l<=r) { int mid=(l+r)/2; init(); num=0; for (int i=1;i<=m1;i++) { int u=X[i],v=Y[i]; jb(u,v+n);jb(u+n,v); jb(v,u+n);jb(v+n,u); } for (int i=m1+1;i<=m1+m2;i++) { int u=X[i],v=Y[i]; jb(u,v);jb(v,u); jb(u+n,v+n);jb(v+n,u+n); } for (int i=0;i<n;i++) for (int j=0;j<n;j++) { if (i==j)continue; if (dist1[i]+dist1[j]>mid)jb(i,j+n); if (dist2[i]+dist2[j]>mid)jb(i+n,j); if (dist1[i]+dist2[j]+tot>mid)jb(i,j); if (dist2[i]+dist1[j]+tot>mid)jb(i+n,j+n); } int sig=0,cnt=0; for (int i=0;i<n+n&&flag;i++) if (!vis[i])dfs(i,sig,cnt); if (flag) { ans=mid; r=mid-1; } else l=mid+1; } } int main() { while (~scanf("%d%d%d",&n,&m1,&m2)) { scanf("%d%d%d%d",&x1,&y11,&x2,&y2); tot=js(x1,y11,x2,y2); for (int i=0;i<n;i++) { scanf("%d%d",&x,&y); dist1[i]=js(x,y,x1,y11); dist2[i]=js(x,y,x2,y2); } for (int i=1;i<=m1+m2;i++) { scanf("%d%d",&X[i],&Y[i]); X[i]--;Y[i]--; } solve(); printf("%d ",ans); } return 0; }