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. 判断ARP欺骗

    转自http://bbs.51cto.com/thread-904594-1.html 网关是服务器或者单独主机设备的话 如果网关是服务器或者单独主机设备的话查询网关MAC地址要简单一些,我们只需要在 ...

  2. 高级同步器:可重用的同步屏障Phaser

    引自:https://shift-alt-ctrl.iteye.com/blog/2302923 在JAVA 1.7引入了一个新的并发API:Phaser,一个可重用的同步barrier.在此前,JA ...

  3. 【读书笔记 - Effective Java】02. 遇到多个构造器参数时要考虑用构建器

    类有多个可选参数的解决方案: 1. 重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读. 2. JavaBeans模式,调用一个无参构造器来创造对象,然后调用sett ...

  4. JSP/Servlet开发——第二章 JSP数据交互(一)

    1. JSP内置对象:JSP内置对象是 Web 容器创建的一组对象:   ●JSP常用的内置对象:out.request.application.session.response等: ●内置对象不需要 ...

  5. HTML中汉字空格占位符

    == 普通的英文半角空格   ==   ==   == no-break space (普通的英文半角空格但不换行)   == 中文全角空格 (一个中文宽度)   ==   == en空格 (半个中文 ...

  6. .Net Core如何在程序的任意位置使用和注入服务

    最近有人问我:我该如何在Startup类之外的地方注入我的服务呢,都写在startup里看着好乱:我该如何在程序的其他地方获取我注入的服务呢: 故我写了这篇博客,文中有不对的地方欢迎指正. 一.如何在 ...

  7. spark源码编译记录

    spark在项目中已经用了一段时间了,趁现在空闲,下个源码编译在IDEA里面阅读下,特此记录过程. 前提已经安装maven和git 1.上官网下载源码的包: 2.然后解压到一个文件夹 3.编译,编译的 ...

  8. python学习笔记:第16天 面向对象02--对象中的成员

    目录 ⼀.类的成员介绍: 二.类的成员-变量 三.类的成员-方法 四.类的成员-属性 五.私有属性 ⼀.类的成员介绍: ⾸先, 什么是类的成员. 很简单. 我么能在类中写什么? 写的内容就是成员. 到 ...

  9. Vue.js核心概念

    # 1. Vue.js是什么? 1). 一位华裔前Google工程师(尤雨溪)开发的前端js库 2). 作用: 动态构建用户界面 3). 特点: * 遵循MVVM模式 * 编码简洁, 体积小, 运行效 ...

  10. JSON初体验(三):FastJson解析

    JSON解析之FastJson(阿里巴巴解析开源) 特点: Fastjson是一个Java语言编写的高性能功能完善的JSON库,它采用的 是一种"假定有序快速匹配"的算法,把JSO ...