zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",Left[i]);
    77         }
    78     }
    79     return 0;
    80 }
    ac代码
  • 相关阅读:
    C# 操作Excel之旁门左道
    C#数据类型、控件、数据类型、ADO.NET等命名规范
    tab 切换函数
    ASP.NET常用JS脚本整理
    实现MSMQ消息加密的安全实践
    关于jQuery中的offset()和position()
    SQL中使用update inner join和delete inner join
    setTimeout和setInterval
    设计漂亮的样式表是一门艺术(译) (转)
    使用jQuery制作手风琴效果(转)
  • 原文地址:https://www.cnblogs.com/zhanzhao/p/3905583.html
Copyright © 2011-2022 走看看