poj3308

题意:一个矩阵,已知其中一些格会降落伞兵,每行每列都有一个武器,可以一次性消灭该行或该列的全部伞兵,每个武器对应不同的价格,若使用多个武器则总价是各个武器价钱的乘积,问消灭所有伞兵最少要多少钱。

分析:最小权覆盖集。难点在于武器总价不是加和而是乘积,那么我们需要把各个单价转化为以e为底的对数,这样再求对数加和的时候其实各个原单价之间是相乘的关系。建立二分图,每行对应一个节点,每列对应一个节点,各点权值等于其武器价钱的以e为底的对数,每个伞兵是连接其所在行列节点的一条边。对这个二分图求最小权独立集。转化为最小割,转化为最大流。

View Code
#include <iostream>

#include <cstdlib>

#include <cstring>

#include <cstdio>

#include <cmath>

using namespace std;



#define inf 0x3f3f3f3f

#define maxn 55

#define maxl 505

#define N maxn * 2

#define E (N + maxl) * 2



int n, m, num;

int s, t;



struct edge

{

    int x, y, nxt;

    double c;

}bf[E];



int ne, head[N], cur[N], ps[N], dep[N];



void addedge1(int x, int y, double c)

{

    bf[ne].x = x;

    bf[ne].y = y;

    bf[ne].c = c;

    bf[ne].nxt = head[x];

    head[x] = ne++;

}



void addedge(int x, int y, double c)

{

    addedge1(x, y, c);

    addedge1(y, x, 0);

}



double flow(int n, int s, int t)

{

    double tr, res = 0;

    int i, j, k, f, r, top;

    while (1)

    {

        memset(dep, -1, n * sizeof(int));

        for (f = dep[ps[0] = s] = 0, r = 1; f !=r;)

            for (i = ps[f++], j = head[i]; j; j = bf[j].nxt)

            {

                if (bf[j].c && -1 == dep[k = bf[j].y])

                {

                    dep[k] = dep[i] + 1;

                    ps[r++] = k;

                    if (k == t)

                    {

                        f = r;

                        break;

                    }

                }

            }

        if (-1 == dep[t])

            break;



        memcpy(cur, head, n * sizeof(int));

        for (i = s, top = 0;;)

        {

            if (i == t)

            {

                for (k = 0, tr = inf; k  < top; ++k)

                    if (bf[ps[k]].c < tr)

                        tr = bf[ps[f = k]].c;

                for (k = 0; k < top; ++k)

                    bf[ps[k]].c -=tr, bf[ps[k]^1].c += tr;

                res += tr;

                i = bf[ps[top = f]].x;

            }

            for (j = cur[i]; cur[i]; j = cur[i] = bf[cur[i]].nxt)

                if (bf[j].c && dep[i] + 1 == dep[bf[j].y])

                    break;

            if (cur[i])

            {

                ps[top++] = cur[i];

                i = bf[cur[i]].y;

            }

            else

            {

                if (0 == top)

                    break;

                dep[i] = -1;

                i = bf[ps[--top]].x;

            }

        }

    }

    return res;

}



void input()

{

    scanf("%d%d%d", &n, &m, &num);

    s = 0;

    t = n + m + 1;

    for (int i = 1; i <= n; i++)

    {

        double a;

        scanf("%lf", &a);

        addedge(s, i, log(a));

    }

    for (int i = n + 1; i <= n + m; i++)

    {

        double a;

        scanf("%lf", &a);

        addedge(i, t, log(a));

    }

    for (int i = 0; i < num; i++)

    {

        int a, b;

        scanf("%d%d", &a, &b);

        addedge(a, n + b, inf);

    }

}



int main()

{

    //freopen("t.txt", "r", stdin);

    int case_num;

    scanf("%d", &case_num);

    while (case_num--)

    {

        ne = 2;

        memset(head, 0, sizeof(head));

        input();

        printf("%.4f\n", exp(flow(n + m + 2, s, t)));

    }

    return 0;

}

你可能感兴趣的:(poj)