【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;
}