学姐的逛街计划-最大费用最大流,线性规划

本文详细解析了如何运用最大费用最大流算法解决学姐的逛街计划问题,通过引入辅助变量和线性规划,将问题转化为网络流模型,并提供了完整的算法实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学姐的逛街计划-最大费用最大流,线性规划

题目描述

题目描述

题解

设第 i i i天是否去逛街为 a [ i ] a[i] a[i] c [ i ] c[i] c[i]表示第i天的智商, a [ i ] = 1 a[i]=1 a[i]=1表示去逛街, a [ i ] = 0 a[i]=0 a[i]=0表示不去
则可得 2 n 2n 2n个不等式
a [ 1 ] + a [ 2 ] + . . . + a [ n ] < = k a[1]+a[2]+...+a[n]<=k a[1]+a[2]+...+a[n]<=k
a [ 2 ] + a [ 3 ] + . . . + a [ n + 1 ] < = k a[2]+a[3]+...+a[n+1]<=k a[2]+a[3]+...+a[n+1]<=k
. . . ... ...
a [ 2 n + 1 ] + . . . . + a [ 3 n ] < = k a[2n+1]+....+a[3n]<=k a[2n+1]+....+a[3n]<=k
c [ 1 ] ∗ a [ 1 ] + c [ 2 ] ∗ a [ 2 ] + . . . + c [ 3 n ] ∗ a [ 3 n ] c[1]*a[1]+c[2]*a[2]+...+c[3n]*a[3n] c[1]a[1]+c[2]a[2]+...+c[3n]a[3n]的最大值
添加一个辅助变量
a [ 1 ] + a [ 2 ] + . . . + a [ n ] + y [ 1 ] = k a[1]+a[2]+...+a[n]+y[1]=k a[1]+a[2]+...+a[n]+y[1]=k
a [ 2 ] + a [ 3 ] + . . . + a [ n + 1 ] + y [ 2 ] = k a[2]+a[3]+...+a[n+1]+y[2]=k a[2]+a[3]+...+a[n+1]+y[2]=k
. . . ... ...
a [ 2 n + 1 ] + . . . . + a [ 3 n ] + y [ 2 n + 1 ] = k a[2n+1]+....+a[3n]+y[2n+1]=k a[2n+1]+....+a[3n]+y[2n+1]=k
0 < = y [ i ] < = k 0<=y[i]<=k 0<=y[i]<=k
将上述不等式相邻两个相减
y [ 1 ] + a [ 1 ] = a [ n + 1 ] + y [ 2 ] − − − ( 1 ) y[1]+a[1]=a[n+1]+y[2]---(1) y[1]+a[1]=a[n+1]+y[2](1)
y [ 2 ] + a [ 2 ] = a [ n + 2 ] + y [ 3 ] − − − ( 2 ) y[2]+a[2]=a[n+2]+y[3]---(2) y[2]+a[2]=a[n+2]+y[3](2)
. . . . . . ...... ......
y [ n + 1 ] + a [ n + 1 ] = a [ 2 n + 1 ] + y [ n + 2 ] − − − ( n + 1 ) y[n+1]+a[n+1]=a[2n+1]+y[n+2]---(n+1) y[n+1]+a[n+1]=a[2n+1]+y[n+2](n+1)
. . . . . . ...... ......
y [ 2 n ] + a [ 2 n ] = a [ 3 n ] + y [ 2 n + 1 ] − − − ( 2 n ) y[2n]+a[2n]=a[3n]+y[2n+1]---(2n) y[2n]+a[2n]=a[3n]+y[2n+1](2n)
根据网络中每个节点流入量等于流出量的性质
将上述等式编号并抽象成网络中的点,变量a[i]和y[i]抽象为网络中的有向边(弧)
问题等价于求最大费用最大流
a [ n + 1 ] a[n+1] a[n+1]为例 可以看成是节点1部分流出量和节点 n + 1 n+1 n+1的部分流入量于是可以建边从 n + 1 n+1 n+1 1 1 1
故根据这些等式可以建图
设源点为 0 0 0,汇点为 2 n + 3 2n+3 2n+3
i i i到n+i连一条弧,流量上限为 1 1 1(因为变量a的取值为1或0),费用为 c [ n + i ] c[n+i] c[n+i], 1 < = i < = n 1<=i<=n 1<=i<=n(针对变量 a a a)
i i i i + 1 i+1 i+1连一条弧,流量上限为 k k k(因为变量y满足 0 < = y < = k 0<=y<=k 0<=y<=k),费用为 0 0 0, 1 < = i < = 2 n − 1 1<=i<=2n-1 1<=i<=2n1(针对变量 y y y
这时发现题目的 k k k还没用上,
于是发现上述等式成立必需满足这两个等式
a [ 1 ] + a [ 2 ] + . . . + a [ n ] + y [ 1 ] = k − − − ( n + 1 ) a[1]+a[2]+...+a[n]+y[1]=k---(n+1) a[1]+a[2]+...+a[n]+y[1]=k(n+1)
a [ 2 n + 1 ] + . . . . + a [ 3 n ] + y [ 2 n + 1 ] = k − − − ( 2 n + 2 ) a[2n+1]+....+a[3n]+y[2n+1]=k---(2n+2) a[2n+1]+....+a[3n]+y[2n+1]=k(2n+2)
于是建一个节点 2 n + 1 2n+1 2n+1
为了满足 2 n + 1 2n+1 2n+1
则由源点向节点2n+1连一条流量上限为 k k k的边,费用为0。
由节点 2 n + 1 2n+1 2n+1向i连一条流量上限为 1 1 1的边,费用为 c [ i ] c[i] c[i] 1 < = i < = n 1<=i<=n 1<=i<=n
源 点 源点 2 n + 1 2n+1 2n+1连一条流量上限为 k k k的边,费用为 0 0 0
同理建一个节点 2 n + 2 2n+2 2n+2
为了满足 2 n + 2 2n+2 2n+2
则由节点 2 n + 2 2n+2 2n+2向汇点连一条流量上限为 k k k的边,费用为 0 0 0
由节点i向 2 n + 2 2n+2 2n+2连一条流量上限为 1 1 1的边,费用为 c [ i ] c[i] c[i] n + 1 < = i < = 2 n n+1<=i<=2n n+1<=i<=2n
建图完毕,剩下就是套算法。

代码

#include<bits/stdc++.h>
#define M 200009
using namespace std;
const int inf=1e9+7; 
int nxt[M],to[M],f[M],w[M],first[M],tot=1;
int vis[M],d[M],now[M],n,m,ret,a[M],k,T;
void add(int x,int y,int z,int v){
	nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z,f[tot]=v;
	nxt[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0,f[tot]=-v;
} 
bool bfs(){
	memset(vis,0,sizeof(vis));
	for(int i=0;i<=T;i++) d[i]=-1;
	queue<int>q;
	d[T]=0,vis[T]=1;
	q.push(T),now[T]=first[T];
	while(q.size()){
		int u=q.front();
		q.pop(),vis[u]=0;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];
			if(w[i^1]&&d[v]<d[u]+f[i^1]){
				d[v]=d[u]+f[i^1];
				now[v]=first[v];
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}return d[0]!=-1;
}
int dfs(int x,int flow){
	if(x==T) return flow;
	int rest=flow,i;
	vis[x]=1;
	for(i=now[x];i&&rest;i=nxt[i]){
		int v=to[i];
		if(!vis[v]&&w[i]&&d[v]==d[x]-f[i]){
			int k=dfs(v,min(rest,w[i]));
			if(k==0){d[v]=0;continue;}
			w[i]-=k,w[i^1]+=k,rest-=k,ret+=k*f[i];
		}
	}vis[x]=0,now[x]=i;
	return flow-rest;
}
void build(){
	for(int i=1;i<=n;i++) add(i,i+n,1,a[i+n]);
	for(int i=1;i<=2*n-1;i++) add(i,i+1,k,0);
	for(int i=1;i<=n;i++) add(2*n+1,i,1,a[i]);
	for(int i=n+1;i<=2*n;i++) add(i,2*n+2,1,a[i+n]);
	add(0,2*n+1,k,0),add(2*n+2,T,k,0);
} 
int zkw(){
	int ans=0,fl=0;
	while(bfs()){
		memset(vis,0,sizeof(vis));
		while(fl=dfs(0,inf)) ans+=fl;
	}return ret;
}
int main(){
	scanf("%d%d",&n,&k),T=2*n+3;
	for(int i=1;i<=3*n;i++) scanf("%d",&a[i]);
	build();
	printf("%d\n",zkw());
	return 0; 
} 

做题启发

1,对于多个不等式,可以引用辅助变量(如变量y)
2,对于在等式左右两边分别出现过的变量,根据网络中每个节点流入量等于流出量的性质,可以考略用网络流建模做

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值