【网络流24题】最长递增子序列问题

原创 2017年01月02日 20:59:53

(网络流24题大多需要spj,所以需要一个有spj的oj,本系列代码均在www.oj.swust.edu.cn测试通过)
这道题据说在codeforces上的数据变成了最长不降,但是本文附上的oj没有这种情况。
这道题的题意就是求出最长上升序列长度,然后每个数只能取一个的情况下最多有多少种方案能取出这么长的序列,第一个数和最后一个数无限多的时候能取出多少个。
首先第一问dp就可以了,而且数据不大,最简单的dp即可。
然后第二问出现了一个数只能选一次的问题,那么就到了网络流的领域了,我们这样实现,将一个点拆分为一个入点和一个出点,入点和出点之间连一条1的流,如果以一个数为尾的最长序列长度为第一问答案的话,那么就从源点向该点连一条容量为1的流,如果最长序列长度为1的话就向汇点连接一条容量为一的流,两个点满足i < j && a[i] < a[j] && f[j]==f[i]+1 则从j向i连接一条容量为1的流,这样的话每一条流都是一个最长的序列,有几条这样的序列第二问的答案就是几。
第三问主要的变化就是1和n的数量发生了变化,那我们只需要将(1,1),(n,n)(s,1)(1,t)(s,n)(n,t)(如果有的话)的流量改为INF再求一边增广路即可。
注意当最长上升子序列为1的情况,这时候理论方案为无穷大(因为1,n无限多),但是根据数据来看只算了一个,将答案取余INF即可

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iomanip>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 100000000
struct bian
{
    int l,r,f;
}a[1000000];
int fir[1000000];
int nex[1000000];
int d[100000];
int s=0,t=99999;
bool bfs()
{
    static int dui[1000000];
    memset(d,-1,sizeof(d));
    int top=1,my_final=2;
    dui[top]=s;
    d[s]=1;
    while(top<my_final)
    {
        int u=dui[top++];
        for(int o=fir[u];o;o=nex[o])
        {
            if(d[a[o].r]==-1 && a[o].f)
            {
                dui[my_final++]=a[o].r;
                d[a[o].r]=d[u]+1;
                if(a[o].r==t) return true;
            }
        }
    }
    return false;
}
int dinic(int u,int flow)
{
    if(u==t) return flow;
    int left=flow;
    for(int o=fir[u];o&&left;o=nex[o])
    {
        if(a[o].f && d[a[o].r]==d[u]+1)
        {
            int temp=dinic(a[o].r,min(left,a[o].f));
            if(!temp) d[a[o].r]=-1;
            left-=temp;
            a[o].f-=temp;
            a[o^1].f+=temp;
        }
    }
    return flow-left;
}
int tot=1;
void add_edge(int l,int r,int f)
{
    a[++tot].l=l;
    a[tot].r=r;
    a[tot].f=f;
    nex[tot]=fir[l];
    fir[l]=tot;
}
int dui[1000000];
int top=0;
int f[1000];
int v[1000];
int main()
{
    int n;
    scanf("%d",&n);
    v[0]=-2147483647;
    f[0]=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        for(int j=0;j<i;j++) if(v[j]<v[i]) f[i]=max(f[i],f[j]+1);
        ans=max(ans,f[i]);
    }
    for(int i=1;i<=n;i++)
    {
        add_edge(i,n+i,1);
        if(i==1 || i==n) dui[++top]=tot;
        add_edge(n+i,i,0);
    }
    for(int i=1;i<=n;i++)
    {
        if(f[i]==ans)
        {
            add_edge(s,i,1);
            if(i==1 || i==n) dui[++top]=tot;
            add_edge(i,s,0);
        }
        if(f[i]==1)
        {
            add_edge(i+n,t,1);
            if(i==1 || i==n) dui[++top]=tot;
            add_edge(t,i+n,0);
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
        {
            if(v[j]<v[i] && f[i]==f[j]+1)
            {
                add_edge(i+n,j,1);
                add_edge(j,i+n,0);
            }
        }
    cout<<ans<<endl;
    int trueans=0;
    while(bfs()) trueans+=dinic(s,INF);
    cout<<trueans<<endl;
    for(int i=1;i<=top;i++)
        a[dui[i]].f=INF;
    while(bfs()) trueans+=dinic(s,INF);
    if(trueans>INF) trueans=trueans%INF;
    cout<<trueans<<endl;
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

网络流24题6. 最长递增子序列问题

动态规划,最大流,拆点
  • KikiDMW
  • KikiDMW
  • 2017年03月03日 10:47
  • 178

code vs [网络流24题] 最长递增子序列问题

1906 最长递增子序列问题  时间限制: 2 s  空间限制: 256000 KB  题目等级 : 大师 Master 题解 ...
  • clover_hxy
  • clover_hxy
  • 2016年02月18日 19:20
  • 604

网络流24题6 最长递增子序列

题目描述给定正整数序列x1,…,xn 。(1)计算其最长递增子序列的长度s。(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中...
  • jpwang8
  • jpwang8
  • 2016年12月26日 21:45
  • 227

长度不超过m的最大连续子序列(dp + 单调队列)

给你n个数,然后让你求最大连续子序列的和,限制条件是连续子序列的长度不超过m。 n,m   就是让你找到一个长度不超过m的区间,区间和最大。 普通的dp转移方程就是 dp[i] = sum[i] - ...
  • SSimpLe_Y
  • SSimpLe_Y
  • 2017年05月13日 12:11
  • 943

noip1999 拦截导弹 (单调队列求解:最长下降子序列+最长上升子序列)

A1120. 拦截导弹 时间限制:1.0s   内存限制:256.0MB   总提交次数:979   AC次数:286   平均分:38.46 将本题分享到:            查看...
  • yuyanggo
  • yuyanggo
  • 2015年08月15日 16:50
  • 1088

动态规划中的单调队列优化

最近经常出现单调队列,斜率优化的题目。看到周围的大神们都会做了,我只能跟上去。 要慢慢来,先学单调队列。 什么类型的DP需要用到常规的单调队列? 类似这样的转移方程可以用到单调队列: f[...
  • A1847225889
  • A1847225889
  • 2017年09月02日 16:19
  • 407

最长递增子序列问题[网络流24题之6]

问题描述: 给定正整数序列 x1,x2,...,xn x_1,x_2,...,x_n 。 (1)(1) 计算其最长递增子序列的长度 s s 。 (2)(2) 计算从给定的序列中最多可...
  • CuSO45H20
  • CuSO45H20
  • 2016年05月21日 14:13
  • 382

【网络流24题】最长递增子序列问题

(网络流24题大多需要spj,所以需要一个有spj的oj,本系列代码均在www.oj.swust.edu.cn测试通过) 这道题据说在codeforces上的数据变成了最长不降,但是本文附上的oj...
  • LZJ209
  • LZJ209
  • 2017年01月02日 20:59
  • 360

nefu487最长递增子序列问题【网络流24题】超详细讲解+模板

description 给定正整数序列x1 , ... , xn 。 (1)计算其最长递增子序列的长度s。 (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。 (3)...
  • zhou_yujia
  • zhou_yujia
  • 2015年09月26日 21:12
  • 562

【codevs 1906】最长递增子序列问题(dp+最大流)

一壶秋月碎离愁,风迷离,雨迷离
  • reverie_mjp
  • reverie_mjp
  • 2016年11月12日 00:20
  • 233
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【网络流24题】最长递增子序列问题
举报原因:
原因补充:

(最多只允许输入30个字)