zoukankan      html  css  js  c++  java
  • 最长递增子序列(cogs 731)

    «问题描述:
    给定正整数序列x1,..., xn。
    (1)计算其最长递增子序列的长度s。
    (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
    (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。

    注意:这里的最长递增子序列即最长不下降子序列!!!
    «编程任务:
    设计有效算法完成(1)(2)(3)提出的计算任务。
    «数据输入:
    由文件alis.in提供输入数据。文件第1 行有1个正整数n(n<=500),表示给定序列的长度。接
    下来的1 行有n个正整数x1,..., xn。
    «结果输出:
    程序运行结束时,将任务(1)(2)(3)的解答输出到文件alis.out中。第1 行是最长
    递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出
    的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
    输入文件示例 输出文件示例
    alis.in
    4

    3 6 2 5

    alis.out

    2
    2
    3

    /*
      第一问很好求,第二问网络流貌似可做(废话),但是想了很久,没想出怎么建图,看了题解才发现自己太弱了。
      完全可以按照但都是求出的f数组的顺序建边,对于第三问,建图的时候将容量设为无限大就好了。 
    */
    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #define N 1010
    #define M 1000010
    #define inf 1000000000
    using namespace std;
    int a[N],f[N],S,T,ans,n;
    int head[N],dis[N],cnt;
    struct node{int v,pre,f;}e[M];
    int dp(){
        f[1]=1;int maxn=1;
        for(int i=2;i<=n;i++){
            int p=0;
            for(int j=i;j>=1;j--)
                if(a[j]<=a[i]) p=max(p,f[j]);
            f[i]=p+1;
            maxn=max(maxn,f[i]);
        }
        return maxn;
    }
    void add(int u,int v,int f){
        e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
        e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
    }
    void build1(){
        cnt=1;memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++){
            if(f[i]==1) add(S,i,1);
            add(i,i+n,1);
            if(f[i]==ans) add(i+n,T,1);
            for(int j=1;j<i;j++)
                if(a[j]<=a[i]&&f[j]+1==f[i])
                    add(j+n,i,1);
        }
    }
    void build2(){
        cnt=1;memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++){
            if(i==1||i==n){
                if(f[i]==1) add(S,i,inf);
                add(i,i+n,inf);
                if(f[i]==ans) add(i+n,T,inf);
            }
            else {
                if(f[i]==1) add(S,i,1);
                add(i,i+n,1);
                if(f[i]==ans) add(i+n,T,1);
            }
            for(int j=1;j<i;j++)
                if(a[j]<=a[i]&&f[j]+1==f[i])
                    add(j+n,i,1);
        }
    }
    bool bfs(){
        memset(dis,-1,sizeof(dis));
        queue<int> q;q.push(S);dis[S]=0;
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].pre)
                if(e[i].f&&dis[e[i].v]==-1){
                    dis[e[i].v]=dis[u]+1;
                    q.push(e[i].v);
                    if(e[i].v==T) return true;
                }
        }
        return dis[T]!=-1;
    }
    int dinic(int x,int f){
        int rest=f;
        if(x==T) return f;
        for(int i=head[x];i;i=e[i].pre)
            if(dis[e[i].v]==dis[x]+1&&e[i].f){
                int t=dinic(e[i].v,min(rest,e[i].f));
                if(!t) dis[e[i].v]=-1;
                rest-=t;
                e[i].f-=t;
                e[i^1].f+=t;
            }
        return f-rest;
    }
    int main(){
        scanf("%d",&n);S=1;T=n*2+1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        ans=dp();printf("%d
    ",ans);
        if(ans==1) {printf("%d
    %d",n,n);return 0;}
        build1();int maxflow=0;
        while(bfs()) maxflow+=dinic(S,inf);
        printf("%d
    ",maxflow);
        build2();maxflow=0;
        while(bfs()) maxflow+=dinic(S,inf);
        printf("%d",maxflow);
        return 0;
    }
  • 相关阅读:
    《Android深入透析》之广播(Broadcast)
    曾经的程序员-《30岁的程序员,你迷惘了吗?》
    30岁的程序员,你迷惘了吗?
    Android: 详解触摸事件如何传递
    关于HTML5服务器发送事件(SSE)
    Android: 在onCreate()中获得对象尺寸
    jxl教程图文详解
    相当牛X的java版星际游戏
    程序员的无奈(十二):终于获得了投资
    图览各编程语言中敲击最多的键
  • 原文地址:https://www.cnblogs.com/harden/p/6476674.html
Copyright © 2011-2022 走看看