• 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;
    }
  • 相关阅读:
    美赛 LaTeX 急救指南
    切比雪夫定理的证明
    【持续更新】一个简洁、易用的美赛 LaTeX 模板: easymcm
    一个形式较精细的 Strling 公式的证明
    数学分析的主线,高等数学的一切:连续函数与“有理”分析
    一个自己稍作修改了的美赛论文 LaTeX 模板
    有关几个特殊命题的证明
    实数系与实数定理(下)
    实数系与实数定理(上)
    Office365完整离线安装包下载及自定义安装教程
  • 原文地址:https://www.cnblogs.com/staginner/p/2645729.html
Copyright © 2020-2023  润新知