題意:
給n個村莊的坐標和兩個特殊點s1,s2的坐標,現在要將每個村莊連到s1或s2上,使n個村莊間的最大距離最小。
分析:
二分任意兩村莊間的最大距離,用2-sat判斷該最大距離是否可行,二分的時候可以順便記錄答案,不用等最後區間為空時再輸出l或l-1。
代碼:
//poj 2749 //sep9 #include#include using namespace std; const int maxN=1024; const int maxL=4000000; vector g[maxN],ng[maxN]; int n,m,cnt,scc,vis[maxN],dfn[maxN]; int x1,y1,x2,y2; int x[maxN],y[maxN]; int a,b; int ap[maxN],aq[maxN],bp[maxN],bq[maxN]; int d[maxN],D; void addegde(int u,int v) { g[u].push_back(v); ng[v].push_back(u); } void dfs(int k) { vis[k]=1; for(int i=g[k].size()-1;i>=0;--i) if(!vis[g[k][i]]) dfs(g[k][i]); dfn[++cnt]=k; } void ndfs(int k) { vis[k]=scc; for(int i=ng[k].size()-1;i>=0;--i) if(!vis[ng[k][i]]) ndfs(ng[k][i]); } void kosaraju() { memset(vis,0,sizeof(vis)); cnt=0; for(int i=1;i<=2*n;++i) if(!vis[i]) dfs(i); memset(vis,0,sizeof(vis)); scc=0; for(int i=2*n;i>=1;--i) if(!vis[dfn[i]]){ ++scc; ndfs(dfn[i]); } } int two_sat(int dis) { int i,j; for(i=1;i<=2*n;++i) g[i].clear(),ng[i].clear(); for(i=1;i<=a;++i){ int p=ap[i],q=aq[i]; addegde(p,q+n); addegde(p+n,q); addegde(q,p+n); addegde(q+n,p); } for(i=1;i<=b;++i){ int p=bp[i],q=bq[i]; addegde(p,q); addegde(q,p); addegde(p+n,q+n); addegde(q+n,p+n); } for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) if(i!=j){ if(d[i]+d[j]>dis){ addegde(i,j+n); addegde(j,i+n); } if(d[i]+d[j+n]+D>dis){ addegde(j+n,i+n); addegde(i,j); } if(d[i+n]+d[j]+D>dis){ addegde(i+n,j+n); addegde(j,i); } if(d[i+n]+d[j+n]>dis){ addegde(i+n,j); addegde(j+n,i); } } kosaraju(); for(i=1;i<=n;++i) if(vis[i]==vis[i+n]) return 0; return 1; } int main() { int i,j; scanf("%d%d%d",&n,&a,&b); scanf("%d%d%d%d",&x1,&y1,&x2,&y2); for(i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]); for(i=1;i<=n;++i){ d[i]=abs(x[i]-x1)+abs(y[i]-y1); d[i+n]=abs(x[i]-x2)+abs(y[i]-y2); } D=abs(x1-x2)+abs(y1-y2); int p,q; for(i=1;i<=a;++i) scanf("%d%d",&ap[i],&aq[i]); for(i=1;i<=b;++i) scanf("%d%d",&bp[i],&bq[i]); int l=0,r=maxL,ans=-1; while(l