网络流(最小割最大流)【POJ3308】

来源:互联网 发布:mysql的好处 编辑:程序博客网 时间:2024/04/30 16:01

【POJ3308】

  题意:简单的说就是有一个方阵,告诉你方阵里的一些位置有一些敌人伞兵,而且你有一些激光枪,这些激光枪有穿透效果,也就是如果摆在第一排的排头话就可以杀死这一排的所有伞兵,当然也可以放在一列的列头可以杀死一列的伞兵。在不同行或列建立激光枪所需的费用不一样,建立这些激光枪的总费用是建立每个激光枪的乘积,求建立激光枪杀死所有伞兵的总费用。输入:第一行是测试数据T, 第二行是行数(r) 列数(c)  伞兵数(l),第三行是建立在i行的激光枪花费的费用,第四行是建立在i列所花费的费用,接着有l行是伞兵的坐标。

  解题思路:该题依然是一个最小割最大流问题,首先就是建图,我们可以把伞兵视为边,行和列视为顶点,再增加一个源点和一个汇点,源点连接每个行,每个列连接汇点,容量分别为在该行和该列建立激光枪的费用,伞兵的坐标视为边,容量为无穷大!根据割的性质,源点和汇点必不连通,因此割边必定存在s->r  r->c  c->t中,将r->c的容量设为无穷大,则不能被选中。这样割边就在s->r  c->t的集合,也就选中了对应的行和列,此时求得的最小割既为答案!    但是改题求得是乘积而不是和,那么问题来了,怎么将乘积变为和计算,那么下面直接附上代码,看完代码应该就明白了

#include<stdio.h>#include<math.h>int main(){    int x, y;   while(~scanf("%d %d", &x, &y))    printf("x和y的积为log(x)+log(y)=%lf\n", (double)exp((double) log(x)+(double)log(y)));}

下面是ac代码:(值得注意的是如果用C++交的话是下面的代码, 如果用G++交的话就把最后printf里的“lf”的l去掉);

#define MAX 110#define INF 10000000#include<string.h>#include<algorithm>#include<math.h>#include<stdio.h>struct Node{    double c, f;}map[MAX][MAX];int pre[MAX];  //pre[i]为增广路径顶点i前一个顶点的序号int queue[MAX]; //数组模拟队列int s, t; //源点,汇点;bool BFS() //BFS求增广路{    int i, cur, qs, qe; //队列当前结点;队列头,队列尾    memset(pre, -1, sizeof(pre));    pre[s] = s;    qs = 0;    qe = 1;    queue[qs] = s;    while(qs < qe)    {        cur = queue[qs++];        for( i = 0; i <= t; i++)        {            if(pre[i] == -1 && map[cur][i].c-map[cur][i].f > 0)            {                queue[qe++] = i;                pre[i] = cur;                if(i == t) return 1;//汇点不在层次网络中            }        }    }    return 0; //汇点不在层次网络中}double maxflow() //求最大流{    double max_flow = 0, min;    int i;    while(BFS())    {        min = INF;        for(i = t; i != s; i = pre[i]) //调整网络        {            if( map[pre[i]][i].c - map[pre[i]][i].f < min)                min = map[pre[i]][i].c - map[pre[i]][i].f;        }        for( i = t; i != s; i = pre[i])        {            map[pre[i]][i].f += min;            map[i][pre[i]].f -= min;        }        max_flow += min;    }    return max_flow; //返回最大流}int main(){    int i, n, m, l, r, cc, w;    double c;    scanf("%d", &w);    while(w--)    {        memset(map, 0, sizeof(map));        scanf("%d%d%d", &n, &m, &l);        s = 0;        t = n+m+1;        构建网络;用对数运算将乘法转化为加法        for( i = 1; i <= n; i++)        {            scanf("%lf", &c);            map[s][i].c = log(c);        }        for( i = 1; i <= m; i++)        {            scanf("%lf", &c);            map[i+n][t].c = log(c);        }        for(i = 1; i <= l; i++)        {            scanf("%d%d", &r, &cc);            map[r][n+cc].c = 10000000;        }        printf("%.4lf\n", exp(maxflow())); //输出时将对数值转换为原值    }    return 0;}


0 0
原创粉丝点击