375. 蚂蚁(最大带权匹配)
首先我们需要将题意转换成我们能处理的意思:
不想交==最短
如此图,a与d,b与c相连则会相交,由于相交所以必有1+2+3+4>5+6,所以a与c,b与d距离最短切不想交
由于相交不然会出现上图的三角形,所以我们控制总和最小,则必不相交...
之后我们跑二分图带权最小即可.
这里用的网络流实现的.
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=210,INF=2e9; int n,link[N],s,t,incf[N],pre[N],c[N],vis[N],tot=1; double dis[N]; struct edge{int y,next,v;double c;}a[N*N*N]; struct node{int x,y;}b1[N],b2[N]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline double distanc(int i,int j) { double x=b1[i].x-b2[j].x; double y=b1[i].y-b2[j].y; //cout<<x<<' '<<y<<endl; return sqrt(x*x+y*y); } inline void add(int x,int y,int v,double c) { a[++tot].y=y;a[tot].v=v;a[tot].c=c;a[tot].next=link[x];link[x]=tot; a[++tot].y=x;a[tot].v=0;a[tot].c=-c;a[tot].next=link[y];link[y]=tot; } inline bool spfa() { queue<int>q;q.push(s); for(int i=s;i<=t;++i) dis[i]=INF; memset(vis,0,sizeof(vis)); dis[s]=0;incf[s]=INF;vis[s]=1; while(!q.empty()) { int x=q.front();q.pop();vis[x]=0; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; //if(x==1&&y==2) cout<<a[i].v<<' '<<a[i].c<<endl; if(!a[i].v) continue; if(dis[y]>dis[x]+a[i].c) { dis[y]=dis[x]+a[i].c; incf[y]=min(incf[x],a[i].v); pre[y]=i; if(!vis[y]) vis[y]=1,q.push(y); } } } if(dis[t]==INF) return false; return true; } inline void updata() { int x=t,o; while(x!=s) { //cout<<x<<endl; if(x>=n+1&&x<=n*2) o=x; else if(x>=1&&x<=n) c[x]=o; int i=pre[x]; a[i].v-=incf[t]; a[i^1].v+=incf[t]; x=a[i^1].y; } } int main() { freopen("1.in","r",stdin); n=read(); s=0;t=n<<1|1; for(int i=1;i<=n;++i) b1[i].x=read(),b1[i].y=read(); for(int i=1;i<=n;++i) b2[i].x=read(),b2[i].y=read(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) add(i,j+n,1,distanc(i,j)); // cout<<distanc(1,1)<<endl; for(int i=1;i<=n;++i) add(s,i,1,0); for(int i=1;i<=n;++i) add(i+n,t,1,0); while(spfa()) updata(); //cout<<c[1]<<endl; for(int i=1;i<=n;++i) printf("%d\n",c[i]-n); return 0; }