大意:
左图为一个坐标轴上的点 其中黑点代表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代码
poj3565Ants【最小权匹配】,布布扣,bubuko.com
时间: 2024-09-30 19:50:04