首页 > 其他分享 >费用流例题

费用流例题

时间:2024-02-28 21:22:04浏览次数:17  
标签:pre 费用 容量 nxt int inf 例题

1.k取方格数

一个矩阵格子,从最左上角出发到最右下角,走k次,每个格子上有一个数,走过一次就变为0,问能取到的所有数字之和最大值。

每个点 i 拆成两个点 i 和 i'(左半边与右半边),两点之间连两条边一条容量为 1,费用为 -a[i], 另一条容量为无穷,费用为0

每个点的右半边与相邻点的左半边连起来,容量为无穷(应该是只要比k大就行),费用为0。

从源点到左上角的点连一条边,容量为 k, 费用为0,从右下角到汇点连一条边,容量为k,费用为0,跑一次最小费用最大流

 

2.小改

此时费用变为,该边上流量的平方,比如一条边容量为10,流量为2,则费用为4

思路:原本的算法只对费用与流量成正比的时候有效,现在变成一个凸函数,不能直接使用,则拆边,把一条容量为n的边拆成n条,分别为

容量为1,费用为 1^2 - 0^2

容量为2,费用为 2^2 - 1^2

......

容量为n, 费用为 n^2 - (n-1)^2

 

3.序列选数

给一个长为 n 的序列,从中分别取出1,2,3,...,n/2个不相邻的数,分别和最大,输出

当 只取一个数的时候,很明显答案就是序列中最大的那个数

使用费用流的思路,当我们要取第二个及以后的数的时候,需要允许反悔,则对

i - 1, i, i + 1,三个数,如果我们取了第 i 个数,那么i-1和i+1就不能取,除非反悔,发现 a[i-1]+a[i+1] >= a[i]

那么只需要在取了第i个点后,将这三个点合并成为一个值为 a[i-1]+a[i+1]-a[i]的新点即可

折叠

#include<bits/stdc++.h>
using namespace std;
const int MXN = 100010, inf = 0x3f3f3f3f;
struct Range{
	int l, pre, nxt, v;
	bool operator<(Range x)const{ return v < x.v;}
}r[MXN];
priority_queue<Range> q;
int main(){
	int t, n, ans, cnt;
	scanf("%d", &t);
	while(t--){
		ans = 0;
		while(!q.empty()) q.pop();
		scanf("%d", &n);
		for(int i = 1; i <= n; ++i){
			scanf("%d", &r[i].v);
			r[i].pre = i-1, r[i].nxt = i+1; // 前驱后继
			q.push((Range){i, 0, 0, r[i].v});
		}
		cnt = n/2;
		while(!q.empty() && cnt){
			Range k = q.top();
			q.pop();
			Range &y = r[k.l];
			if(y.v != k.v) continue;     // 被合并的点,此时就不能再选了
			ans += y.v, cnt--;
			printf("%d\n", ans);
			Range &x = r[y.pre], &z = r[y.nxt];
			if(y.pre < 1 && y.nxt > n) continue; // 不符合规定的点
			else if(y.pre == 0) y.v = z.v = -inf, r[z.nxt].pre = 0;  //如果这个点没有前驱或者后继,直接删点
			//没有反悔的可能
			else if(y.nxt > n) x.v = y.v = -inf, r[x.pre].nxt = y.nxt;
			else{
				x.v += z.v - y.v, x.nxt = z.nxt;
				y.v = z.v = -inf;
				r[z.nxt].pre = y.pre;
				k.v = x.v, k.l = y.pre;
				q.push(k);
			}
			// 否则对于三个点, 保留最左边的点,旁边两点删去
		}
	}
    return 0;
}

标签:pre,费用,容量,nxt,int,inf,例题
From: https://www.cnblogs.com/xxx3/p/18041887

相关文章

  • 期望 dp 例题 7 选
    期望概率\(dp\)例题。【例题1】期望分数\(link\)设在\(i\)的得分是\(x\),有\(x_i\)个连续的\(1.\)\[E(i)=p_i[(x_i+1)-x_i^3]+(1-p_i)E(0)+E(i-1)\]多项式乘法化简,最后得到\[E(i-1)+p_i[3x_i^2+3x_i+1]\]问题转移到\(E^2(x_i)\)以及\(E(x_i)\)\[E^2(x_i)=p_iE......
  • 免费工具 Winsw 和 NSSM 适合对服务管理功能有一定要求的用户,且不想花费额外费用;SRVAN
    免费工具:SRVANY:优点:允许将任何可执行文件转换为服务。Windows自带工具,无需额外安装。简单易用,适合基本的服务管理需求。缺点:功能相对简单,不支持高级的服务管理功能。不再得到官方支持和更新,可能存在一些稳定性问题。Winsw:优点:简单易用,提供了一个简单的配置......
  • 【博客】网络流&&费用流
    网络流前言当听到网络流量之后感觉是在充话费网络流(network-flows)是一种类比水流的解决问题方法,与线性规划密切相关。它模拟了水流从起点经过复杂的网络流向终点的过程就像自来水厂的水经过无数根水管子流到了家里而最大流就是最多有多少水流到了家里算法流程EK......
  • 反悔贪心(模拟费用流)
    反悔贪心(模拟费用流)贪心本身是不能反悔的,但如果当前最优解不是全局最优解,我们就需要通过反悔来贴近全局最优解。一般用堆来实现,即堆中维护当前可以用来反悔的决策,然后每次取最优的决策。其实从更一般的角度,反悔贪心就是建出费用流模型,然后用数据结构来模拟增广的操作。一些例题......
  • 【C++】STL string类例题新思路记录(编写一个程序,告诉用户输入的句子包含多少个元音字
    题干:编写一个程序,告诉用户输入的句子包含多少个元音字母。 方案一:1、创建一个普通函数,依次传入5个元音字母对查找字符串进行检测。2、函数通过依次传入的单个元音字母,循环查找整个字符串最后返回统计值。1#include<string>2#include<iostream>3usingnamespace......
  • 树与图的宽度优先遍历例题
    #include<iostream>#include<algorithm>#include<cstring>usingnamespacestd;constintN=100010;intn,m;inth[N],e[N],ne[N],idx;intd[N],q[N];intans=N;voidadd(inta,intb){e[idx]=b,ne[idx]=h[a],......
  • 学编程千万别上培训机构:费用、通用性和实战经验都不行
    学编程是一项极富挑战性的任务,而不是一件能够轻松完成的事情。很多人在学习编程的时候都会考虑去培训机构学习,然而,在现实中,并不是每个人都能从培训机构中获得真正的技术提升,相反,有许多学习编程的人,尤其是想从事IT行业的人,其实更适合采用其他的学习方式。以下是一些理有据的观点,用来......
  • 【多线程例题】使用三个线程,分别可以打印A,B,C。要求实现三个线程协同打印,顺序打印出ABC
    顺序打印-进阶版方法一:三个线程竞争同一个锁,通过count判断是否打印三个线程分别打印A,B,C方法一:通过count计数打印(三个线程上同样的锁,打印一个,召唤所有锁,如果不满足条件,则wait等待,锁自动解锁)方法二:/***有三个线程,分别只能打印A,B和C*要求按顺序打印ABC,打印10次*输出示......
  • 【板子】费用流(zkw/Dinic)
    //lgp3381#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstintN=(int)5e3+3;constintM=(int)5e4+4;constllINF=0x3f3f3f3f;intcur[N];lldis[N];boolvis[N];boolinq[N];intedgeid=1;inthead[N];structedge{in......
  • 3.C语言学习--分支与循环例题分析2
    1.有三个数,将他们按照从大到小的顺序输出intmain(){ inta=0; intb=0; intc=0; scanf("%d%d%d",&a,&b,&c); inttmp=0; if(a<b) { tmp=a; a=b; b=tmp; } if(a<c) { tmp=a; a=c; c=tmp; } if(b<c)......