首页 > 代码库 > poj3565Ants【最小权匹配】

poj3565Ants【最小权匹配】

大意:

左图为一个坐标轴上的点  其中黑点代表ants 白点代表apple 问怎样安排ants匹配apple才能使人一两条边不想交

分析:

 

如左图,我们假设a->d,b->c为一个最佳匹配  交点为e

那么ad+bc = ae+ ed + be + ec = (ae + ec) + (be + ed)  该值大于ac+bd

所以匹配为最佳匹配不成立

因此我们只要求出二分图的最小匹配就是结果了

但是wa了;

wa的代码:

 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5  6 const long long maxn = 105; 7 const long long INF = 10000000000; 8  9 10 long long W[maxn][maxn];11 long long Lx[maxn], Ly[maxn];12 long long Left[maxn];13 bool S[maxn], T[maxn];14 15 long long n;16 17 bool match(long long i) {18     S[i] = true;19     for(long long j = 1; j <= n; j++) if (Lx[i]+Ly[j] == W[i][j] && !T[j]){20         T[j] = true;21         if (!Left[j] || match(Left[j])){22             Left[j] = i;23             return true;24         }25     }26     return false;27 }28 29 void update() {30     long long a = INF;31     for(long long i = 1; i <= n; i++) if(S[i])32         for(long long j = 1; j <= n; j++) if(!T[j])33             a = min(a, Lx[i]+Ly[j] - W[i][j]);34     for(long long i = 1; i <= n; i++) {35         if(S[i]) Lx[i] -= a;36         if(T[i]) Ly[i] += a;37     }38 }39 40 void KM() {41     for(long long i = 1; i <= n; i++) {42         Left[i] = Lx[i] = Ly[i] = 0;43         for(long long j = 1; j <= n; j++)44             Lx[i] = max(Lx[i], W[i][j]);45     }46     for(long long i = 1; i <= n; i++) {47         for(;;) {48             for(long long j = 1; j <= n; j++) S[j] = T[j] = false;49             if(match(i)) break; else update();50         }51     }52 }53 54 55 struct Node {56     long long x, y;57 }ant[maxn], apple[maxn];58 59 60 long long dist(Node n1, Node n2) {61     return (n1.x - n2.x) * (n1.x - n2.x) + (n1.y - n2.y) * (n1.y - n2.y);62 }63 64 int main() {65     while(EOF != scanf("%lld",&n)) {66         for(long long i = 1; i <= n; i++) scanf("%lld %lld",&ant[i].x, &ant[i].y);67         for(long long i = 1; i <= n; i++) scanf("%lld %lld",&apple[i].x, &apple[i].y);68         memset(W, 0, sizeof(W));69         for(long long i = 1; i <= n; i++) {70             for(long long j = 1; j <= n; j++) {71                 W[i][j] = -dist(apple[i], ant[j]);72             }73         }74         KM();75         for(long long i = 1; i <= n; i++) {76             printf("%lld\n",Left[i]);77         }78     }79     return 0;80 }
wa的代码

想了好长时间终于知道哪儿错了

我只是用的距离的平方做的比较

也就是说 a^2 + b ^ 2 > c ^ c + d ^ 2 不能推出 a + b > c + d

比如1^2 + 100^2 > 50 ^ 2 + 51 ^2 但是 1 + 100 < 51 + 52

所以平方比较是错的

ac代码如下:

 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6  7 const int maxn = 105; 8 const double INF = 1000000000; 9 10 double W[maxn][maxn];11 double Lx[maxn], Ly[maxn];12 int Left[maxn];13 bool S[maxn], T[maxn];14 15 int n;16 17 bool match(int i) {18     S[i] = true;19     for(int j = 1; j <= n; j++) if ( (abs(Lx[i]+Ly[j] - W[i][j]) < 0.00000001) && !T[j]){20         T[j] = true;21         if (!Left[j] || match(Left[j])){22             Left[j] = i;23             return true;24         }25     }26     return false;27 }28 29 void update() {30     double a = INF;31     for(int i = 1; i <= n; i++) if(S[i])32         for(int j = 1; j <= n; j++) if(!T[j])33             a = min(a, Lx[i]+Ly[j] - W[i][j]);34     for(int i = 1; i <= n; i++) {35         if(S[i]) Lx[i] -= a;36         if(T[i]) Ly[i] += a;37     }38 }39 40 void KM() {41     for(int i = 1; i <= n; i++) {42         Left[i] = 0;43         Lx[i] = Ly[i] = 0.0;44         for(int j = 1; j <= n; j++)45             Lx[i] = max(Lx[i], W[i][j]);46     }47     for(int i = 1; i <= n; i++) {48         for(;;) {49             for(int j = 1; j <= n; j++) S[j] = T[j] = false;50             if(match(i)) break; else update();51         }52     }53 }54 55 struct Node {56     double x, y;57 }ant[maxn], apple[maxn];58 59 double dist(Node n1, Node n2) {60     return sqrt((n1.x - n2.x) * (n1.x - n2.x) + (n1.y - n2.y) * (n1.y - n2.y));61 }62 63 int main() {64     //freopen("3565.txt","r",stdin);65     while(EOF != scanf("%d",&n)) {66         for(int i = 1; i <= n; i++) scanf("%lf %lf",&ant[i].x, &ant[i].y);67         for(int i = 1; i <= n; i++) scanf("%lf %lf",&apple[i].x, &apple[i].y);68         memset(W, 0, sizeof(W));69         for(int i = 1; i <= n; i++) {70             for(int j = 1; j <= n; j++) {71                 W[i][j] = -dist(apple[i], ant[j]);72             }73         }74         KM();75         for(int i = 1; i <= n; i++) {76             printf("%d\n",Left[i]);77         }78     }79     return 0;80 }
ac代码