zoukankan      html  css  js  c++  java
  • poj3565 Ants(KM)

    题目链接
    翻译链接

    分析:
    因为节点有黑白两色,我们不难想到建立一个二分图
    X部:苹果树
    Y部:蚁群
    边权:两点之间的欧几里得距离

    然而,有一个不相交的限制
    好像KMgg了
    (gg这个梗好像出自魔兽,神tomato魔兽)
    但是我们不能就这么笃定的放弃
    假设现在有两对点的连线是这样的
    这里写图片描述
    假设最佳完美匹配中存在这两条相交的边
    那么一定有dis(a1,b2)+dis(a2,b1)>=dis(a1,b1)+dis(a2,b2)
    因此如果改为a1—b1和a2—b2后总长度会变小,
    最佳矛盾,因此最佳方案中不可能出现两条相交直线

    tip

    很多题,会一些迷惑人的条件,要学会明辨

    double慎用

    一开始我担心精度问题,就用的整形去做的
    这样能跑出样例,但是交上去得到的只有WA

    改成double之后跑不出样例
    (输出是4 2 3 5 1)
    但是依赖于SP,就A了
    这下彻底推翻了我的世界观

    //这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #define ll long long
    
    using namespace std;
    
    const double INF=1e17;
    const double eps=1e-8;
    const int N=110;
    int belong[N];
    bool L[N],R[N];
    int n;
    double ant[N][2],tree[N][2];
    double W[N][N],Lx[N],Ly[N],slack[N];
    
    double sqr(double x){return x*x;}
    
    int match(int i)
    {
        L[i]=1;
        for (int j=1;j<=n;j++)
            if (!R[j])
            {
                double v=Lx[i]+Ly[j]-W[i][j];
                if (fabs(v)<eps)
                {
                    R[j]=1;
                    if (!belong[j]||match(belong[j]))
                    {
                        belong[j]=i;
                        return 1;
                    }
                }
                else slack[j]=min(slack[j],v);
            }
        return 0;
    }
    
    void KM()
    {
        memset(Ly,0,sizeof(Ly));
        memset(belong,0,sizeof(belong));
        for (int i=1;i<=n;i++)
        {
            Lx[i]=W[i][1];
            for (int j=2;j<=n;j++)
                Lx[i]=max(Lx[i],W[i][j]);
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++) slack[j]=INF;
            while (1)
            {
                memset(L,0,sizeof(L));
                memset(R,0,sizeof(R));
                if (match(i)) break;
                double a=INF;
                for (int j=1;j<=n;j++) 
                    if (!R[j]) a=min(a,slack[j]);
                for (int j=1;j<=n;j++)
                    if (L[j]) Lx[j]-=a;
                for (int j=1;j<=n;j++)
                    if (R[j]) Ly[j]+=a,
                    slack[j]-=a;
            }
        }
    }
    
    void print()
    {
        for (int i=1;i<=n;i++)
            printf("%d
    ",belong[i]);
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            scanf("%lf%lf",&ant[i][0],&ant[i][1]);
        for (int i=1;i<=n;i++)
            scanf("%lf%lf",&tree[i][0],&tree[i][1]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                W[j][i]=-sqrt(sqr(ant[i][0]-tree[j][0])+sqr(ant[i][1]-tree[j][1]));
        KM();
        print();
        return 0;
    }
  • 相关阅读:
    MySQL的max()函数使用时遇到的小问题
    scp命令需要指定端口时要紧跟在scp后
    linux系统之间基于密钥对免输入密码登陆
    c++的引用用法
    预测模型
    mysql出现ERROR 1366 (HY000):的解决办法
    R语言可视化--颜色
    R语言可视化--ggplot函数
    R语言可视化--qplot函数
    R语言可视化二
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673105.html
Copyright © 2011-2022 走看看