zoukankan      html  css  js  c++  java
  • poj 3686 The Windy's 夜

    http://poj.org/problem?id=3686

    拆点+KM算法

    题目大意:

    n个玩具在m台机器上完成所需时间个不同

    一台机器只有完成一个玩具的的制作才能继续完成其它的

    问你n给玩具完成制作最小平均时间

    思路转自

    http://blog.sina.com.cn/s/blog_6af663940100mw9t.html

    此题构图很巧妙。设n个订单的执行时间分别为t1,t2…tn,则n个订单的总的执行时间是
    t1*n+t2*(n-1)+t3*(n-2)+…+tn-1*2+tn。将每个机器j拆成n个点,第k个点表示倒数第k个订单在此机器上完成,连边权值为:tmp[i][j]*k。这样就转换成了求二分图最小权匹配的问题了。KM算法,把权值设为负值求最大权匹配

    求的是最小平均时间 把时间转换为负的 就可以求最大匹配了

    我个人直接用三维数组储存的,这样原来的右组就由一维变成了二维

    其它的都一样了

    代码及其注释:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    const int MAX=0x7ffffff;
    const int N=51;
    int paytime[N][N][N];//拆点后花费时间,
    int a[N];//左组顶标
    int b[N][N];//右组顶标
    bool lv[N];//左组是否在交叉树内
    bool rv[N][N];//右组是否在交叉树内
    int n,m;
    int f[N][N];//右组指向
    bool dfs(int x)//匈牙利算法找匹配
    {
        lv[x]=true;
        for(int i=1;i<=m;++i)
        {
            for(int j=1;j<=n;++j)
            {
                if(!rv[i][j]&&a[x]+b[i][j]==paytime[x][i][j])
                {
                    rv[i][j]=true;
                    if(f[i][j]==-1||dfs(f[i][j]))
                    {
                        f[i][j]=x;
                        return true;
                    }
                }
            }
        }
        return false;
    }
    int KM()
    {
        memset(b,0,sizeof(b));
        for(int i=1;i<=n;++i)
        {
            a[i]=-MAX;
            for(int j=1;j<=m;++j)
            {
                for(int l=1;l<=n;++l)
                {
                    a[i]=max(a[i],paytime[i][j][l]);//左组顶标初始最大
                }
            }
        }
    
        memset(f,-1,sizeof(f));
        for(int w=1;w<=n;++w)
        {
            while(1)
            {
              memset(lv,false,sizeof(lv));
              memset(rv,false,sizeof(rv));
              if(dfs(w))//匹配的话直接退出循环找下一个 否则减d继续找
              break;
              int d=MAX;
              for(int i=1;i<=n;++i)
              {
                if(lv[i])
                {
                    for(int j=1;j<=m;++j)
                    {
                        for(int l=1;l<=n;++l)
                        {
                            if(!rv[j][l])
                            {
                                d=min(d,a[i]+b[j][l]-paytime[i][j][l]);//找最小变化量
                            }
                        }
                    }
                }
              }
              for(int i=1;i<=n;++i)
              {
                if(lv[i])
                a[i]-=d;
              }
              for(int j=1;j<=m;++j)
              {
                for(int l=1;l<=n;++l)
                {
                    if(rv[j][l])
                    b[j][l]+=d;
                }
              }
            }
        }
        int sum=0;
        for(int j=1;j<=m;++j)
        {
            for(int l=1;l<=n;++l)
            {
                if(f[j][l]!=-1)
                sum-=paytime[f[j][l]][j][l];//最优匹配总值
            }
        }
        return sum;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d %d",&n,&m);
            int k;
            for(int i=1;i<=n;++i)
            {
                for(int j=1;j<=m;++j)
                {
                     scanf("%d",&k);
                     for(int l=1;l<=n;++l)
                     {
                         paytime[i][j][l]=-(k*l);//拆点
                     }
                }
            }
            printf("%.6f\n",1.0*(KM())/n);
        }
        return 0;
    }
    
    
  • 相关阅读:
    处理了一个“服务器能ping得通,但telnet连接失败”导致数据库登录不了的问题
    解决了一个oracle登录缓慢的问题
    今天解决了一个mysql远程登录和本机ip登录都失败的问题
    c++笔记
    c语言笔记
    常见并发与系统设计
    linux网络IO笔记
    linux文件IO全景解析
    linux网络协议笔记
    长大后才懂的蜡笔小新 ​​​​
  • 原文地址:https://www.cnblogs.com/liulangye/p/2544054.html
Copyright © 2011-2022 走看看