1 条题解

  • 0
    @ 2025-5-25 17:25:29

    这段代码实现了一个基于最大流的算法,核心是通过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
    上传者