Description

It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the Mars. Recently, the commanders of the Earth are informed by their spies that the invaders of Mars want to land some paratroopers in the × n grid yard of one their main weapon factories in order to destroy it. In addition, the spies informed them the row and column of the places in the yard in which each paratrooper will land. Since the paratroopers are very strong and well-organized, even one of them, if survived, can complete the mission and destroy the whole factory. As a result, the defense force of the Earth must kill all of them simultaneously after their landing.

In order to accomplish this task, the defense force wants to utilize some of their most hi-tech laser guns. They can install a gun on a row (resp. column) and by firing this gun all paratroopers landed in this row (resp. column) will die. The cost of installing a gun in the ith row (resp. column) of the grid yard is ri (resp. ci ) and the total cost of constructing a system firing all guns simultaneously is equal to the product of their costs. Now, your team as a high rank defense group must select the guns that can kill all paratroopers and yield minimum total cost of constructing the firing system.

Input

Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing three integers 1 ≤ m ≤ 50 , 1 ≤ n ≤ 50 and 1 ≤ l ≤ 500 showing the number of rows and columns of the yard and the number of paratroopers respectively. After that, a line with m positive real numbers greater or equal to 1.0 comes where the ith number is ri and then, a line with n positive real numbers greater or equal to 1.0 comes where the ith number is ci. Finally, l lines come each containing the row and column of a paratrooper.

Output

For each test case, your program must output the minimum total cost of constructing the firing system rounded to four digits after the fraction point.

题目大意:有一个m行n列的矩阵,矩阵上有L个点,每行每列各有一个权值,要求选出若干行和列,覆盖矩阵上所有的点,同时要求这些选出的行和列的权的乘积最小。

思路:首先要求的是乘积最小,利用公式ln(a*b) = lna + lnb,把求乘积转化成求和,在输出答案的时候再来个exp(ans)。这题为最小点权覆盖,建网络流图:从源点S建一条边到每一行,容量为该行的权值的log,从每一列到汇点T建一条边,容量为该权值的log。对每一个点(i, j),从第i行建一条边到第j列,容量为正无穷大。跑最大流,求出最小割,再弄个exp就是答案。

小证明:每一个简单割(只割掉与源点或汇点有关联的边,即不割掉行与列之间的边)都唯一对应着一个可行的方案。记所割掉的与源点关联的点为cut(S),其余与S关联的点为else(S),割掉的与汇点关联的点为cut(T),其余与T关联的点未else(T),我们选上的点就是cut(S)与cut(T)。那么对于cut(S)与cut(T)之间的边,都有点对应(由割的定义,允许有从cut(S)到cut(T)的边);对于else(S)与cut(T)之间的边,都会有一点在cut(T)上;对于else(T)与cut(S)之间的边,都会有一点在cut(S)上;根据割的定义,简单割所对应的方案不会有else(S)到else(T)之间的边。故所有简单割所唯一对应的方案都是合法的。而最小割就对应着那些选上的点的权值之和(题目中为log之和),我们要权值最小,那么最小割就是答案,所以最大流就是答案(exp之后)。

PS:虽然不是每一个方案都对应着一个简单割,但是不对应着简单割的方案,一定多选了几个点……

PS2:此题流量浮点数,所以要注意,EPS据说要选输出精度的两倍,据说这题不用两倍也行。至于我看到有人说,由于精度问题INF不能选太大的,选1e2就够了,不过其实不一定有影响,我的代码就没有影响,INF太大的话增减流量的时候,INF-minFlow精度差太多结果还会是INF,不过它变不变好像跟我没什么关系……反正又不会减到0……

PS3:我现在才发现我的ISAP模板里面不能有点0,之前那题是怎么AC的呢>_<

代码(0MS):

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std; const int MAXN = ;
const int MAXE = ;
const double INF = 1e100;
const double EPS = 1e-; inline int sgn(double x) {
if(fabs(x) < EPS) return ;
return x > ? : -;
} struct SAP {
int head[MAXN], dis[MAXN], cur[MAXN], pre[MAXN], gap[MAXN];
int to[MAXE], next[MAXE];
double flow[MAXE];
int ecnt, n, st, ed; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, double c) {
to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; flow[ecnt] = ; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d->%d %lf\n", u, v, c);
} void bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<int> que; que.push(ed);
dis[ed] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
++gap[dis[u]];
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(sgn(flow[p ^ ]) && dis[v] > n) {
dis[v] = dis[u] + ;
que.push(v);
}
}
}
} double Max_flow(int ss, int tt, int nn) {
st = ss; ed = tt; n = nn;
double ans = , minFlow = INF;
for(int i = ; i <= n; ++i) {
cur[i] = head[i];
gap[i] = ;
}
int u = pre[st] = st;
bfs();
while(dis[st] < n) {
bool flag = false;
for(int &p = cur[u]; p; p = next[p]) {
int &v = to[p];
if(sgn(flow[p]) && dis[u] == dis[v] + ) {
flag = true;
minFlow = min(minFlow, flow[p]);
pre[v] = u;
u = v;
if(u == ed) {
ans += minFlow;
while(u != st) {
u = pre[u];
flow[cur[u]] -= minFlow;
flow[cur[u] ^ ] += minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(sgn(flow[p]) && dis[v] < minDis) {
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == ) break;
++gap[dis[u] = minDis + ];
u = pre[u];
}
return ans;
}
} G; int main() {
int T, n, m, l, a, b;
double x;
scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &n, &m, &l);
G.init();
int ss = n + m + , tt = n + m + ;
for(int i = ; i <= n; ++i) {
scanf("%lf", &x);
G.add_edge(ss, i, log(x));
}
for(int i = ; i <= m; ++i) {
scanf("%lf", &x);
G.add_edge(i + n, tt, log(x));
}
for(int i = ; i <= l; ++i) {
scanf("%d%d", &a, &b);
G.add_edge(a, b + n, INF);
//G.add_edge(b + n, a, INF);
}
printf("%.4f\n", exp(G.Max_flow(ss, tt, tt)));
}
}

POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)的更多相关文章

  1. POJ 3308 Paratroopers (对数转换+最小点权覆盖)

    题意 敌人侵略r*c的地图.为了消灭敌人,可以在某一行或者某一列安置超级大炮.每一个大炮可以瞬间消灭这一行(或者列)的敌人.安装消灭第i行的大炮消费是ri.安装消灭第j行的大炮消费是ci现在有n个敌人 ...

  2. poj 3308 Paratroopers(二分图最小点权覆盖)

    Paratroopers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8954   Accepted: 2702 Desc ...

  3. POJ - 2125 Destroying The Graph (最小点权覆盖)

    题意:给一张图,现在要删去所有的边,删去一个点的所有入边和所有出边都有其对应\(W_{i+}\)和\(W_{i-}\).求删去该图的最小花费,并输出解 分析:简而言之就是用最小权值的点集去覆盖所有的边 ...

  4. poj3308 Paratroopers 最大流 最小点权覆盖

    题意:有一个n*m的矩阵,告诉了在每一行或者每一列安装大炮的代价,每一个大炮可以瞬间消灭这一行或者这一列的所有敌人,然后告诉了敌人可能出现的L个坐标位置,问如何安置大炮,使花费最小.如果一个敌人位于第 ...

  5. POJ - 3308 Paratroopers (最小点权覆盖)

    题意:N*M个格点,K个位置会有敌人.每行每列都有一门炮,能打掉这一行(列)上所有的敌人.每门炮都有其使用价值.总花费是所有使用炮的权值的乘积.求最小的总花费. 若每门炮的权值都是1,就是求最小点覆盖 ...

  6. POJ 3308 Paratroopers(最小点权覆盖)(对数乘转加)

    http://poj.org/problem?id=3308 r*c的地图 每一个大炮可以消灭一行一列的敌人 安装消灭第i行的大炮花费是ri 安装消灭第j行的大炮花费是ci 已知敌人坐标,同时消灭所有 ...

  7. poj 3308(最小点权覆盖、最小割)

    题目链接:http://poj.org/problem?id=3308 思路:裸的最小点权覆盖,建立超级源点和超级汇点,将源点与行相连,容量为这行消灭敌人的代价,将列与汇点相连,容量为这列消灭敌人的代 ...

  8. POJ3308 Paratroopers(最小割/二分图最小点权覆盖)

    把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运 ...

  9. POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)

    题意 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,现在我们想把这个图的边都删除掉,需要的最小花费是多少. 思路 很明显的二分图最小点权覆盖 ...

随机推荐

  1. Hibernate基础入门

    Hibernate是一个开放源代码的对象关系映射框架,它将POJO与数据库表之间建立映射关系.是全自动的ORM框架,可以自动生成SQL语句并自动执行.它对JDBC进行了非常轻量级的封装,使程序员可以随 ...

  2. Ubuntu之C++开发环境的搭建

    初学Linux,今天反复卸载与重装微软商店的Ubuntu好几次,终于解锁了在Ubuntu上搭建C++开发环境的正确姿势, 搭建了一个非常简单的开发环境:简单到什么地步呢?只是简单地配置了一下编辑器,安 ...

  3. 简单json---转树形json

    var data = [ {"fileName":"navone","layFilterId":"layadmin-system- ...

  4. java实现验证码功能主要代码

    package com.baojuan.servlet; import java.awt.Color;import java.awt.Font;import java.awt.Graphics2D;i ...

  5. vuejs 解决跨域访问问题

    首先: config/index.js下面的proxyTable配置您的服务访问基本地址,将changeOrigin设置为true即可,然后在你需要访问接口的地方,这样使用,以下是我的工程代码(前提是 ...

  6. 虚拟机(unbutun16.04)设置静态ip

    电脑上装了虚拟机,想用xshell连接,无奈按照默认的网络设置方式每次重启了虚拟机后都要修改ip才能访问,这怎么能忍,经过一番折腾终于搞定这个问题了,解决步骤如下: 大步骤分为两步:其一是主机的设置, ...

  7. PHP Mysql数据库连接

    1,date_default_timezone_set('PRC');//获取北京时区      header("Content-Type:text/html;charset=utf-8&q ...

  8. Hive--关联表(join)

    在hive中,关联有4种方式: 内关联:join on 左外关联:left join on 右外关联:right join on 全外关联:full join on 另外还有一种可实现hive笛卡儿积 ...

  9. IOS和Android系统区别详解

    IOS系统(非开源,不可扩展) iphone沙盒机制解释:应用程序位于文件系统的严格限制部分,程序不能直接访问其他应用程序. 1.iOS的编程语言Objective-C 2.IOS采用的是沙盒运行机制 ...

  10. Kylin 几个sql报错原因 汇总

    Can't create EnumerableAggregate! while executing SQL由distinct count引起的错误 null while executing SQLjo ...