HDU 3998 Sequence(LIS+最大流-Dinic)

来源:互联网 发布:unity3d射击游戏源码 编辑:程序博客网 时间:2024/05/17 07:55

Description
给出一个长度为n的序列,求其最长上升子序列的长度和满足最长长度的子序列的个数
Input
多组用例,每组用例第一行为一整数n表示序列长度,第二行n个整数表示该序列,以文件尾结束输入
Output
对于每组用例,第一行输出最长上升子序列长度,第二行输出不同的最长上升子序列个数
Sample Input
4
3 6 2 5
Sample Output
2
2
Solution
以dp[i]表示以i结尾的最长上升子序列长度,用朴素的O(n*2)或者优化过的O(n*logn)做法得到dp数组后,考虑将所有最长上升子序列表示在一个网络中:
两排点,因为序列中每个元素在LIS中只能出现一次,从i到i+n建流量为1的边;
dp[i]=1,从源点s到i建流量为1的边;
dp[i]=m,从i+n到汇点e建流量为1的边;
dp[j]=dp[i]+1&&j>i&&a[j]>a[i],从i+n到j建流量为1的边
那么问题就转化为在这个网络中求最大流,跑一边Dinic即可
Code

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<queue>using namespace std;#define maxn 2222 #define maxm 2222222#define INF 0x3f3f3f3fint head[maxn],cur[maxn],d[maxn],st[maxm],s,e,no;//s为源点,e为汇点,n为点数,no为边数 int a[maxn],dp[maxn],n;//dp[i]表示最长上升子序列,n表示序列长度 int LIS(int a[]){    for(int i=1;i<=n;i++)dp[i]=1;    for(int i=1;i<=n;i++)        for(int j=i+1;j<=n;j++)            if(a[j]>a[i])                dp[j]=max(dp[j],dp[i]+1);    int ans=0;    for(int i=1;i<=n;i++)ans=max(ans,dp[i]);    return ans;}struct point{    int u,v,flow,next;    point(){};    point(int x,int y,int z,int w):u(x),v(y),next(z),flow(w){};}p[maxm];void add(int x,int y,int z)//从x到y建容量为z的边 {    p[no]=point(x,y,head[x],z);//前向弧,标号为偶     head[x]=no++;    p[no]=point(y,x,head[y],0);//后向弧,标号为奇     head[y]=no++;}void init()//初始化 {    memset(head,-1,sizeof(head));    no=0;}bool bfs(){    int i,x,y;    queue<int>q;    memset(d,-1,sizeof(d));    d[s]=0;     q.push(s);    while(!q.empty())    {        x=q.front();            q.pop();        for(i=head[x];i!=-1;i=p[i].next)        {            if(p[i].flow&& d[y=p[i].v]<0)            {                d[y]=d[x]+1;                if(y==e)                        return true;                q.push(y);            }        }    }    return false;}int dinic()//最大流 {    int i,loc,top,x=s,nowflow,maxflow=0;    while(bfs())    {        for(i=s;i<=e;i++)               cur[i]=head[i];        top=0;        while(true)        {            if(x==e)            {                nowflow=INF;                for(i=0;i<top;i++)                {                    if(nowflow>p[st[i]].flow)                    {                        nowflow=p[st[i]].flow;                        loc=i;                    }                }                for(i=0;i<top;i++)                {                    p[st[i]].flow-=nowflow;                    p[st[i]^1].flow+=nowflow;                }                maxflow+=nowflow;                top=loc;                    x=p[st[top]].u;            }            for(i=cur[x];i!=-1;i=p[i].next)                if(p[i].flow&&d[p[i].v]==d[x]+1)                     break;            cur[x]=i;            if(i!=-1)            {                st[top++]=i;                x=p[i].v;            }            else             {                if(!top)                        break;                d[x]=-1;                x=p[st[--top]].u;            }        }    }    return maxflow;}int main(){    while(~scanf("%d",&n))     {        for(int i=1;i<=n;i++)scanf("%d",&a[i]);        int m=LIS(a);        init();        s=0,e=2*n+1;        for(int i=1;i<=n;i++)        {            add(i,i+n,1);            if(dp[i]==1)add(s,i,1);            if(dp[i]==m)add(i+n,e,1);            for(int j=i+1;j<=n;j++)                if(dp[j]==dp[i]+1&&a[j]>a[i])                    add(i+n,j,1);        }        int ans=dinic();        printf("%d\n%d\n",m,ans);       }    return 0;}
0 0