网络流二十四题

网络流二十四题

网络流是个好东西,希望我也会。

网络流?\(orz\ zsy!!!!!\)

P2766 最长不下降子序列问题

考虑我们是如何\(dp\)这个\(LIS\)的。

我们是倒着推,设置\(dp(i)\)代表以\(i\)为起点的\(LIS\)是多少。转移太显然了
\[
dp(i)=max\{dp(j)\}+1,data[i]\le data[j]
\]
想一想一个合法的\(LIS\)方案代表着什么,代表着它是由这个式子一个一个推出来的。

考虑一个数字只能用一次,那么我们直接拆成两个点\(v_0,v_1\)分别代表一个数字的入度和出度,连一条\(v_1v_2,cap=1\)的边。这样就模拟了一个数字可以被前面多个都相中但是只能往后面相中一个的要求。

考虑如何构造方案,这个东西是个灵感,就是还原\(dp\)的过程,这样就可以得到合法方案。

模型这样建立
\[
(i_0,i_1,1)
\(S,i_0,inf),dp(i)=1
\(i_1,T,inf),dp(k)=ans
\]
这样就好了。先咕咕咕。

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define RP(t,a,b)  for(register int t=(a),edd=(b);t<=edd;++t)
#define ERP(t,a)   for(register int t=head[a];t!=-1;t=e[t].nx)
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define pushup(pos) (seg[pos]=seg[pos<<1]+seg[pos<<1|1])
TMP inline ccf qr(ccf b){
    register char c=getchar();register int q=1;register ccf x=0;
    while(c<48||c>57)q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
    return q==-1?-x:x;}
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Max(ccf a,ccf b,ccf c){return Max(a,Max(b,c));}
TMP inline ccf Min(ccf a,ccf b,ccf c){return Min(a,Min(b,c));}
TMP inline void READ(ccf* _arr,int _n){RP(t,1,_n)_arr[t]=qr((ccf)1);}
//----------------------template&IO---------------------------

const int maxn=5e2+15;
const int maxm=maxn<<3;
int dp[maxn];
int data[maxn];
const int inf=0x3f3f3f3f;
int n,S,T;
struct E{
    int to,w,nx;
}e[maxm<<1],tmp[maxm<<1];
int cnt(-1);
int head[maxm];
int id[maxn][2];
int sz;
int ans1,ans2,ans3;
int d[maxm];
int cur[maxm];

inline void add(int fr,int to,int w,bool f){
    e[++cnt]=(E){to,w,head[fr]};head[fr]=cnt;
    if(f) add(to,fr,0,0);
}

queue < int > q;
inline bool bfs(){
    while(not q.empty()) q.pop();
    RP(t,1,sz) cur[t]=head[t],d[t]=inf+1;
    d[S]=1;q.push(S);
    while(not q.empty()){
    register int now=q.front();q.pop();
    if(now==T) break;
    ERP(t,now){
        if(d[e[t].to]>d[now]+1&&e[t].w>0){
        d[e[t].to]=d[now]+1;
        q.push(e[t].to);
        }
    }
    }
    return d[T]<inf;
}

int dfs(int now,int fl){
    if(now==T||!fl) return fl;
    register int ret=0;
    for(register int t=cur[now],en;t!=-1;t=e[t].nx){
    cur[now]=t;
    if(d[e[t].to]==d[now]+1){
        en=dfs(e[t].to,Min(fl,e[t].w));
        if(en){e[t].w-=en;e[t^1].w+=en;fl-=en;ret+=en;}
        if(not fl)break;
    }
    }return ret;
}

inline void dinic(int& ret){while(bfs()) ret+=dfs(S,inf);}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    memset(head,-1,sizeof head);
    n=qr(1);
    READ(data,n);
    RP(t,1,n) dp[t]=1;ans1=1;
    DRP(t,n,1) RP(i,t+1,n) if(data[t]<=data[i]) ans1=Max((dp[t]=Max(dp[t],dp[i]+1)),ans1);
    S=++sz;T=++sz;
    DRP(t,n,1){
    id[t][0]=++sz;id[t][1]=++sz;
    add(id[t][0],id[t][1],1,1);
    if(dp[t]==1){add(id[t][1],T,inf,1);}
    if(dp[t]==ans1){add(S,id[t][0],inf,1);}
    RP(i,t+1,n) if(data[i]>=data[t]&&dp[i]+1==dp[t]) add(id[t][1],id[i][0],1,1);
    }
    RP(t,0,cnt) tmp[t]=e[t];
    dinic(ans2);
    RP(t,0,cnt) e[t]=tmp[t];
    add(id[1][0],id[1][1],inf,1);
    add(id[n][0],id[n][1],inf,1);
    dinic(ans3);
    if(ans1==1) ans2=ans3=n;
    printf("%d\n%d\n%d\n",ans1,ans2,ans3);
    return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/10486807.html

时间: 2024-11-05 12:35:14

网络流二十四题的相关文章

网络流二十四题之餐巾计划问题

题目传送门 这题的思路我觉得five20巨佬讲的已经非常清晰了,所以就推荐一下他的题解,我就只放代码了 //It is made by HolseLee on 7th Feb 2018 //Luogu.org P1251 #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<queue> #inc

网络流二十四题之魔术球问题

P2765 魔术球问题 题目描述 «问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在n根柱子上最多能放多少个球.例如,在4 根柱子上最多可放11 个球. «编程任务: 对于给定的n,计算在n根柱子上最多能放多少个球. 输入输出格式 输入格式: 第1 行有1个正整数n,表示柱子数. 输出格式: 程序运行结束时,将n 根柱子上最

网络流二十四题 分配问题

分配问题 题目描述 有 nn 件工作要分配给 nn 个人做.第 ii 个人做第 jj 件工作产生的效益为 c_{ij}cij? .试设计一个将 nn 件工作分配给 nn 个人做的分配方案,使产生的总效益最大. 输入输出格式 输入格式: 文件的第 11 行有 11 个正整数 nn ,表示有 nn 件工作要分配给 nn 个人做. 接下来的 nn 行中,每行有 nn 个整数 c_{ij}cij? ??,表示第 ii 个人做第 jj 件工作产生的效益为 c_{ij}cij? . 输出格式: 两行分别输出

从零开始学android&lt;android事件的处理方式.二十四.&gt;

在android中一共有 多种事件,每种事件都有自己相对应的处理机制 如以下几种 1 单击事件 View.OnClickListener public abstract void onClick (View v) 单击组件时触发 2 单击事件 View.OnLongClickListener public abstract boolean onLongClick (View v) 长按组件时触发 3 键盘事件 View.OnKeyListener public abstract boolean

code第一部分:数组 第十四题 雨水问题

code第一部分:数组 第十四题 雨水问题 Given n non-negative integers representing an elevation map where the width of each bar is 1, computehow much water it is able to trap after raining.For example, Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. 分析: 解决方案1 对于每个柱子,找到其左右两

实验二十四:SD卡模块

  驱动SD卡是件容易让人抓狂的事情,驱动SD卡好比SDRAM执行页读写,SD卡虽然不及SDRAM的麻烦要求(时序参数),但是驱动过程却有猥琐操作.除此此外,描述语言只要稍微比较一下C语言,描述语言一定会泪流满面,因为嵌套循环,嵌套判断,或者嵌套函数等都是它的痛.. 史莱姆模块是多模块建模的通病,意指结构能力非常脆弱的模块,暴力的嵌套行为往往会击垮模块的美丽身躯,好让脆弱结构更加脆弱还有惨不忍睹,最终搞垮模块的表达能力.描述语言预想驾驭SD卡,关键的地方就是如何提升模块的结构能力.简单而言,描述

攻城狮在路上(叁)Linux(二十四)--- linux设置开机挂载及镜像文件挂载

虽然可以手动进行文件系统的挂载,但是每次都手动挂载就会很麻烦,开机挂载的目的就是实现文件系统的自动挂载. 一.开机挂载:/etc/fstab及/etc/mtab 主要是通过修改/etc/fstab文件的配置来实现. fstab是开机时的设置,实际文件系统的挂载是记录到/etc/mtab和/proc/mounts这两个文件中. 1.系统挂载的限制: A.根目录/必须挂载,而且一定是最先挂载的,要先于其他mount point. B.其他挂载点必须为已新建的目录,可以任意指定. C.所有挂载点在同一

全栈JavaScript之路( 二十四 )DOM2、DOM3, 不涉及XML命名空间的扩展

(一)DocumentType 类型的变化新增三个属性: publicId,systemId,internalSubset(内部子集) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" [<!ELEMENT name (#PCDATA)>] > 通过, document.doc

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意