1 条题解
-
0
这段代码实现了一个基于最大流的算法,核心是通过Edmonds-Karp(EK)算法解决一个特殊的最优化问题,结合了对数变换来处理乘法关系。
算法原理
问题建模:
将问题转化为网络流模型,其中:
源点(0)连接到前m个节点,边权为log(a)(a为输入的数值)。
后n个节点连接到汇点(m+n+1),边权为log(b)(b为输入的数值)。
l条边连接前m个节点与后n个节点(通过偏移m),边权设为无穷大(表示可以无限流通)。核心思想:
利用对数性质将乘法转换为加法(log(ab) = log(a)+log(b)),通过最大流计算路径上的最大对数和,最终通过指数转换回原问题的最大值。算法流程:
SPFA寻路:使用SPFA算法寻找从源点到汇点的增广路径,记录路径上的最小残留容量。
EK算法更新:通过不断寻找增广路径并更新残留网络,直到无法找到新路径,累加所有广流量(对数和)。
结果转换:将最大对数和通过exp()转换为原问题的最大值。关键步骤
图的构建:
源点到供应节点(前m个)的边权为log(供应值),需求节点(后n个)到汇点的边权为log(需求值),中间连接边权为无穷大。最大流计算:
利用EK算法计算源点到汇点的最大流,此时最大流的和即为所有可能路径中log值的最大值。结果转换:
由于log(a×b) = log(a)+log(b),因此exp(最大流和)即为原问题中路径乘积的最大值。总结
该算法通过网络流模型和对数变换,将乘法优化问题转化为加法优化问题,利用经典的EK最大流算法求解,最终通过指数函数还原为原问题的解。
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #include <stdio.h> #include <string> #include <queue> #include <cmath> #include <stack> #include <map> #include <set> #define eps 1e-7 //#define M 1000100 //#define LL __int64 #define LL long long #define INF 0x3f3f3f3f #define PI 3.1415926535898 const int maxn = 110; using namespace std; double c[110][110]; int pre[maxn]; double f[maxn]; int n, m; double sum; double spfa(int s, int t) { memset(pre, -1 , sizeof(pre)); memset(f , 0 , sizeof(f)); queue<int>q; while(!q.empty()) q.pop(); q.push(s); f[s] = INF; pre[s] = 0; while(!q.empty()) { int temp = q.front(); q.pop(); if(temp == t) break; for(int i = 0; i <= n+m+1; i++) { if(c[temp][i] > 0 && pre[i] == -1) { pre[i] = temp; f[i] = min(c[temp][i], f[temp]); q.push(i); } } } return f[t]; } void EK(int s, int t) { while(1) { double temp = spfa(s, t); if(temp == 0) break; for(int i = t; i != s; i = pre[i]) { c[pre[i]][i] -= temp; c[i][pre[i]] += temp; } sum += temp; } } int main() { int t, l; cin >>t; while(t--) { cin >>m>>n>>l; memset(c, 0 , sizeof(c)); for(int i = 1; i <= m; i++) { double a; cin >>a; c[0][i] = log(a); } for(int i = 1; i <= n; i++) { double a; cin >>a; c[i+m][n+m+1] = log(a); } for(int i = 1; i <= l; i++) { int x, y; cin >>x>>y; c[x][y+m] = INF; } sum = 0; EK(0, m+n+1); cout<<fixed<<setprecision(4)<<exp(sum)<<endl; } return 0; }
- 1
信息
- ID
- 2309
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者