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

    POJ_3686

        看到这个题目后,首先一个思路就是相当于安排每个东西是第几次交给哪个机器做,这样就可以把每个机器拆成N个点当成二分图匹配的题目来做了。但是遇到的最大的问题就是,每个东西的总制造时间会依赖与前面制造的东西,这样每个东西的制造时间就不能独立计算,也就不能用二分图匹配去做了。

        但实际上计算这些东西总的制造时间还有另外一种方式,就是对于每个物品而言,除了计算它本身消耗的时间,同时计算上后面的物品会因为它的制造而额外增加的时间。比如如果制造当前这个物品需要的时间是t,而后面还有k个物品要制造,那么就等同于这个物品一共消耗了t+k*t的时间。这样转化之后就会发现计算每个物品的制造时间就仅仅依赖与后面有多少个物品,而不再依赖于这些物品是什么了,这样就可以用二分图匹配来做了:将每个机器都拆成N个点,分别表示是倒数第几次在这个机子上做的,然后建图用KM求解二分图最优匹配即可。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXN 60
    #define MAXM 2510
    #define INF 0x3f3f3f3f
    int N, M, xM[MAXN], yM[MAXM], g[MAXN][MAXN], G[MAXN][MAXM], MAX;
    int A[MAXN], B[MAXM], slack, visx[MAXN], visy[MAXM];
    void init()
    {
        int i, j, k;
        MAX = 0;
        scanf("%d%d", &N, &M);
        for(i = 1; i <= N; i ++)
            for(j = 1; j <= M; j ++)
            {
                scanf("%d", &g[i][j]);
                MAX = std::max(MAX, g[i][j] * N);
            }
        for(i = 1; i <= N; i ++)
            for(j = 1; j <= M; j ++)
                for(k = 1; k <= N; k ++)
                    G[i][N * (j - 1) + k] = MAX - k * g[i][j];
    }
    int searchpath(int cur)
    {
        int i;
        visx[cur] = 1;
        for(i = 1; i <= N * M; i ++)
            if(!visy[i])
            {
                int t = A[cur] + B[i] - G[cur][i];
                if(t == 0)
                {
                    visy[i] = 1;
                    if(yM[i] == -1 || searchpath(yM[i]))
                    {
                        yM[i] = cur, xM[cur] = i;
                        return 1;
                    }
                }
                else
                    slack = std::min(slack, t);
            }
        return 0;
    }
    void solve()
    {
        int i, j, ans = 0;
        memset(yM, -1, sizeof(yM));
        memset(B, 0, sizeof(B));
        for(i = 1; i <= N; i ++)
        {
            A[i] = 0;
            for(j = 1; j <= N * M; j ++) A[i] = std::max(A[i], G[i][j]);
        }
        for(i = 1; i <= N; i ++)
            for(;;)
            {
                slack = INF;
                memset(visx, 0, sizeof(visx));
                memset(visy, 0, sizeof(visy));
                if(searchpath(i)) break;
                for(j = 1; j <= N; j ++) if(visx[j]) A[j] -= slack;
                for(j = 1; j <= N * M; j ++) if(visy[j]) B[j] += slack;    
            }
        for(i = 1; i <= N; i ++) ans += MAX - G[i][xM[i]];
        printf("%.6f\n", (double)ans / N);
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t --)
        {
            init();
            solve();    
        }
        return 0;
    }
  • 相关阅读:
    MDK软件2020年到期和谐方法
    TinyMCE插件CodeSample前后端应用
    KEIL MDK编译后的代码量和RAM使用详解
    pdf密码解除工具
    Keil c中自定义带可变参数的printf函数
    关于"云服务器被检测到对外攻击已阻断该服务器对其它服务器端口的访问"的解决措施
    在 __CC_ARM 编译器环境下,使用$Sub$$ 与 $Super$$ 的“补丁”功能
    thinkphp前台html格式化输出日期
    ELINK编程器典型场景之序列号烧写
    数据在数组中存储的顺序:小端 OR 大端模式 详解
  • 原文地址:https://www.cnblogs.com/staginner/p/2645729.html
Copyright © 2011-2022 走看看