LA4043 - Ants(二分图完备最佳匹配KM)
大致题意:
平面上有n个白点和n个黑点,求一种完美匹配使他们间的连线不相交
思路:要注意到,若有两种匹配相交,总能够当成对角线补成四边形,然后选四边形的两个边作为匹配就不会相交,并且一定匹配后的距离和缩短了,简单的几何知识,显然最小权匹配不会出现相交情况
防止被卡精度用了龙龙
// Accepted C++11 0.079 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <string> #include <vector> #include <cstdio> #include <ctime> #include <bitset> #include <algorithm> #define SZ(x) ((int)(x).size()) #define ALL(v) (v).begin(), (v).end() #define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i) #define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i) #define REP(i,n) for ( int i=1; i<=int(n); i++ ) #define rep(i,n) for ( int i=0; i<int(n); i++ ) using namespace std; typedef long long ll; #define X first #define Y second typedef pair<ll,ll> pii; template <class T> inline bool RD(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } template <class T> inline void PT(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) pt(x / 10); putchar(x % 10 + '0'); } const int N = 100+10; const ll inf = 1LL<<50; pii poix[N],poiy[N]; int n; ll mp[N][N]; ll dis(int x,int y){ ll a = poix[x].X-poiy[y].X, b = poix[x].Y-poiy[y].Y; return (a*a+b*b); } int link[N]; ll lx[N],ly[N]; //y中各点匹配状态,x,y中的点标号 ll sla[N]; bool visx[N],visy[N]; bool DFS(int x) { visx[x] = true; REP(y,n){ if(visy[y])continue; ll tmp = lx[x] + ly[y] - mp[x][y]; if(tmp == 0){ visy[y] = true; if(link[y] == -1 || DFS(link[y])){ link[y] = x; return true; } } else if(sla[y] > tmp) sla[y] = tmp; } return false; } ll KM() { memset(link,-1,sizeof(link)); memset(ly,0,sizeof(ly)); REP(i,n){ lx[i] = -inf; REP(j,n) lx[i] = max(lx[i],mp[i][j]); } REP(x,n){ REP(i,n) sla[i] = inf; while(true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(DFS(x)) break; ll d = inf; REP(i,n) if(!visy[i]) d = min(d,sla[i]); REP(i,n){ if(visx[i]) lx[i] -= d; if(visy[i])ly[i] += d; else sla[i] -= d; } } } ll res = 0; REP(i,n) if(link[i] != -1) res += mp[link[i]][i]; return res; } int main(){ bool flag = 0; while(~scanf("%d",&n)){ if(flag) puts(""); flag = 1; REP(i,n) RD(poix[i].X),RD(poix[i].Y); REP(i,n) RD(poiy[i].X),RD(poiy[i].Y); REP(x,n) REP(y,n) mp[y][x] = -sqrt(dis(x,y))*10000000; KM(); REP(i,n) printf("%d\n",link[i]); } //Print a blank line between datasets. }