nefu487最长递增子序列问题

来源:互联网 发布:大数据发布人的姿势 编辑:程序博客网 时间:2024/06/05 00:58

最长递增子序列问题

Time Limit 1000ms

Memory Limit 65536K

description

给定正整数序列x1 , ... , xn 。(1)计算其最长递增子序列的长度s。(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。设计有效算法完成(1)(2)(3)提出的计算任务。
Sample Input

3 6 2 5

Sample Output

2

2

3

分析:建模方法是应用了一种分层图的思想,把图每个顶点i按照F[i]的不同分为了若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长上升子序列。如果a[i]<a[j]&&f[i]+1==f[j],则从j到i连一条边。

第三问就是将从源点和汇点出发的边流量变成oo即可

#include<cstdio>using namespace std;const int mm=1111111;const int mn=1111;const int oo=1000000000;int node,src,dest,edge;int ver[mm],flow[mm],next[mm];int head[mn],work[mn],dis[mn],q[mn];inline int min(int a,int b){    return a<b?a:b;}inline void prepare(int _node,int _src,int _dest){    node=_node,src=_src,dest=_dest;    for(int i=0;i<node;++i)head[i]=-1;    edge=0;}void addedge(int u,int v,int c)//加边{    ver[edge]=v;flow[edge]=c;next[edge]=head[u];head[u]=edge++;    ver[edge]=u;flow[edge]=0;next[edge]=head[v];head[v]=edge++;}bool Dinic_bfs()//将一个网络分层{    int i,u,v,l,r=0;    for(i=0;i<node;i++)        dis[i]=-1;    dis[q[r++]=src]=0;    for(l=0;l<r;l++)        for(i=head[u=q[l]];i>=0;i=next[i])            if(flow[i]&&dis[v=ver[i]]<0)            {                dis[q[r++]=v]=dis[u]+1;                if(v==dest) return 1;            }    return 0;}int Dinic_dfs(int u,int exp)//多路增广,从源点开始,用dfs从前一层向后一层反复寻找增广路{    if(u==dest) return exp;    for(int &i=work[u],v,tmp;i>=0;i=next[i])    {        if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)        {            flow[i]-=tmp;//如果该边不是最佳路径中的边,回溯时需要使用反向边            flow[i^1]+=tmp;            return tmp;        }    }    return 0;}int Dinic_flow()//求最大流{    int i,ret=0,delta;    while(Dinic_bfs())    {        for(i=0;i<node;i++)            work[i]=head[i];        while(delta=Dinic_dfs(src,oo))  ret+=delta;    }    return ret;}int main(){   // freopen("input.txt","r",stdin);    //freopen("output.txt","w",stdout);    int u,v,n,a[mn],f[mn],ans;    while(scanf("%d",&n)!=-1)    {        prepare(n+2,n+1,0);        ans=0;        for(u=1;u<=n;++u)        {            scanf("%d",&a[u]);            f[u]=1;            for(v=1;v<u;++v)                if(a[v]<a[u]&&f[v]>=f[u])f[u]=f[v]+1;            if(f[u]>ans)ans=f[u];        }        printf("%d\n",ans);        a[0]=-oo,f[0]=0,f[++n]=ans+1,a[n]=oo;        for(u=1;u<=n;++u)            for(v=0;v<u;++v)                if(a[v]<a[u]&&f[v]+1==f[u])addedge(u,v,1);        printf("%d\n",ans=Dinic_flow());        for(u=head[1];u>=0;u=next[u])            if(ver[u]==0)flow[u]=oo;        for(u=head[n];u>=0;u=next[u])            if(ver[u]==n-1)flow[u]=oo;        ans+=Dinic_flow();        printf("%d\n",ans);    }}


原创粉丝点击