poj3308Paratroopers(最小割)

题目请戳这里

题目大意:给一个n*m的矩阵,给一些点(ri,ci)表示该点在第ri行第ci列。现在要覆盖所有的点,已知覆盖第i行代价为Ri,覆盖第j列代价为Cj。总代价是累乘的,求最小总代价能覆盖所有的点。

题目分析:最小割。增加一个超级源点和超级汇点,源点到行连边,边权为覆盖行的代价,每列到汇点建边,边权为覆盖该列的代价。对于给定的点对,ri->cj连边,边权无穷大。求一个最小割即可。因为根据割的性质,会将图分成2部分,一部分含源点,一部分含汇点,那么这个割集的边只可能为s->ri、ri->cj、cj->t中的某些边,而ri->cj权是无穷大的,所以不会选这些边,因此割集必在s->ri和cj->t中,那么割集中的边就代表选中要覆盖的行和列,因为要总代价最小,所以求出最小割就是最小总代价。

因为总代价是累乘的,所以要化乘法为加法,取对数。

trick:输出浮点数的时候%.f,%.lf会WA。。。

详情请见代码:

 

#include <iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

const int N = 105;

const int M = 5500;

const double inf = 100000000.0;

const double eps = 1e-8;

int m,n,l,num;

struct node

{

    double c;

    int to,next,pre;

}arc[M];

int head[N],sta[N],que[N],cnt[N],dis[N],rpath[N];

void build(int s,int e,double cap)

{

    arc[num].to = e;

    arc[num].c = cap;

    arc[num].next = head[s];

    head[s] = num ++;

    arc[num - 1].pre = num;

    arc[num].pre = num - 1;

    arc[num].to = s;

    arc[num].c = 0.0;

    arc[num].next = head[e];

    head[e] = num ++;

}

void re_Bfs()

{

    int i,front,rear;

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

    {

        dis[i] = n + m + 2;

        cnt[i] = 0;

    }

    front = rear = 0;

    dis[n + m + 1] = 0;

    cnt[0] = 1;

    que[rear ++] = n + m + 1;

    while(front != rear)

    {

        int u = que[front ++];

        for(i = head[u];i != -1;i = arc[i].next)

        {

            if(arc[arc[i].pre].c < eps || dis[arc[i].to] < n + m + 2)

                continue;

            dis[arc[i].to] = dis[u] + 1;

            cnt[dis[arc[i].to]] ++;

            que[rear ++] = arc[i].to;

        }

    }

}

void ISAP()

{

    re_Bfs();

    int i,u;

    double maxflow = 0.0;

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

        sta[i] = head[i];

    u = 0;

    while(dis[0] < n + m + 2)

    {

        if(u == n + m + 1)

        {

            double curflow = inf;

            for(i = 0;i != m + n + 1;i = arc[sta[i]].to)

                curflow = min(curflow,arc[sta[i]].c);

            for(i = 0;i != m + n + 1;i = arc[sta[i]].to)

            {

                arc[sta[i]].c = arc[sta[i]].c - curflow;

                arc[arc[sta[i]].pre].c = arc[arc[sta[i]].pre].c + curflow;

            }

            maxflow = maxflow + curflow;

            u = 0;

        }

        for(i = sta[u];i != -1;i = arc[i].next)

            if(arc[i].c > eps && dis[arc[i].to] + 1 == dis[u])

                break;

        if(i != -1)

        {

            sta[u] = i;

            rpath[arc[i].to] = arc[i].pre;

            u = arc[i].to;

        }

        else

        {

            if((-- cnt[dis[u]]) == 0)

                break;

            sta[u] = head[u];

            int Min = m + n + 2;

            for(i = sta[u];i != -1;i = arc[i].next)

                if(arc[i].c > eps)

                    Min = min(Min,dis[arc[i].to]);

            dis[u] = Min + 1;

            cnt[dis[u]] ++;

            if(u != 0)

                u = arc[rpath[u]].to;

        }

    }

    printf("%.4lf\n",pow(10.0,maxflow));

}

int main()

{

    int t,i;

    int a,b;

    double x;

    scanf("%d",&t);

    while(t --)

    {

        memset(head,-1,sizeof(head));

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

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

        {

            scanf("%lf",&x);

            build(0,i,log10(x));

        }

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

        {

            scanf("%lf",&x);

            build(n + i,m + n + 1,log10(x));

        }

        while(l --)

        {

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

            build(a,n + b,inf);

        }

        ISAP();

    }

    return 0;

}

//568K	16MS


 

 

你可能感兴趣的:(oop)