加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ 3308 最小点权覆盖 最大流

(2010-09-21 17:17:15)
标签:

poj

3308

最小点权覆盖

最大流

it

分类: 网络流

题目描述:

敌人侵略r*c的地图。为了消灭敌人,可以在某一行或者某一列安置超级大炮。

每一个大炮可以瞬间消灭这一行(或者列)的敌人。

安装消灭第i行的大炮消费是ri。

安装消灭第j行的大炮消费是ci

现在有n个敌人,告诉你这n个敌人的坐标,让你 同时 消灭这些敌人,为你最小花费是多少。

花费的定义:每个大炮消费的乘积。

解题报告:

花费是乘积,那么转化成log之后就是求和了。所以转化为求最小的和是多少。

一个敌人在a行b列,那么他可以被大炮ra,或者cb消灭。

建立二分图:左边是r行,右边是c列。一个敌人在a行b列,就连接左边的点a和右边的点b。这样,一条边就表示了消灭一个敌人。

那么选取一些点,是这些点的权值之和最小,同时覆盖所有的边(敌人),就是我们的答案了。显然,问题转化为:最小点权覆盖。建图如下:

二分图x和y两部分。

一个超级源点s,和x连接,容量是x的权值。

一个超级汇点t,y和t连接,容量是y的权值。

如果x中点a和y中点b有边,连接ab,权值无限大。

最大流(最小割)就是答案。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define Max 1000000
#define size 200
#define eps 1e-8
struct edge{int from, to, next; double val;}e[140000];
int v[size], que[size], dis[size], cnt, cur[size];
void insert(int from, int to, double va)
{
    e[cnt].from = from, e[cnt].to = to; e[cnt].val = va;
    e[cnt].next = v[from];v[from] = cnt++;
    e[cnt].from = to, e[cnt].to = from; e[cnt].val = 0;
    e[cnt].next = v[to];v[to] = cnt++;
}
bool bfs(int n, int s, int t)
{
    int head, tail, id;
    head = tail = 0; que[tail++] = s;
    memset(dis, -1, sizeof(int) * n);dis[s] = 0;
    while(head < tail) // bfs,得到顶点i的距s的最短距离dis[i]
        for(id = v[que[head++]]; id != -1; id = e[id].next)
            if (e[id].val > eps && dis[e[id].to] == -1)
            {
                dis[e[id].to] = dis[e[id].from] + 1;
                que[tail++] = e[id].to;
                if (e[id].to == t) return true;
            }
    return false;
}

double Dinic(int n, int s, int t)
{
    double maxflow = 0, tmp; int i;
    while(bfs(n, s, t))
    {
        int u = s, tail = 0;
        for(i = 0; i < n; i++) cur[i] = v[i];
        while(cur[s] != -1)
            if (u != t && cur[u] != -1 && e[cur[u]].val > eps && dis[u] != -1 && dis[u] + 1 == dis[e[cur[u]].to])
            {que[tail++] = cur[u]; u = e[cur[u]].to;}
            else if (u == t)
            {
                for(tmp = 1000000, i = tail - 1; i >= 0; i--) tmp = min(tmp, e[que[i]].val);
                for(maxflow += tmp, i = tail - 1; i >= 0; i--)
                {
                    e[que[i]].val -= tmp;
                    e[que[i] ^ 1].val += tmp;
                    if (fabs(e[que[i]].val) <= eps) tail = i;
                }
                u = e[que[tail]].from;
            }
            else
            {
                while(tail > 0 && u != s && cur[u] == -1) u = e[que[--tail]].from;
                cur[u] = e[cur[u]].next;
            }
    }
    return maxflow;
}
int tt, n, m, l, a, b;
int main()
{
    scanf("%d", &tt);
    while(tt--)
    {
        scanf("%d%d%d", &n, &m, &l);
        int s = 0, t = n + m + 1; double tmp;
        memset(v, -1, sizeof(int) * (t + 1)); cnt = 0;
        for(int i = 1; i <= n && scanf("%lf", &tmp); i++) insert(s, i, log(tmp));
        for(int j = 1; j <= m && scanf("%lf", &tmp); j++) insert(j + n, t, log(tmp));
        while(l-- && scanf("%d%d", &a, &b)) insert(a, b + n, 1000000);
        tmp = Dinic(t + 1, s, t);
        printf("%.4f\n", exp(tmp));
    }
    return 0;
}

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有