[网络流24题]最长上升子序列问题

来源:互联网 发布:登陆淘宝卖家中心 编辑:程序博客网 时间:2024/05/29 19:17

PowerOj1741
对于第一个小问我们可以跑一遍dp,求得ans1,和f[]数组,f[i]表示以i结尾的最长上升子序列
对于第二问和第三问,我们考虑把第i个数拆成两个点,ai与bi。
考虑这样建边:
1. 连接ai,bi,限制为1的边
2. 如果f[i]等于ans1,那么连接bi,t,限制为1的边
3. 如果f[i]等于1,连接s,ai,限制为1的边
4. 如果f[i]=f[j]+1且a[i]>a[j],连接一条bj,ai,限制为1的边
对于第二问,我们跑一遍最大流就是答案了。
对于第三问,我们考虑把<s,a1>,<bn,t>,<a1,b1>,<an,bn>这四条边的限制改成无限大再跑一遍最大流就可以了。

    #include<iostream>    #include<iomanip>    #include<cmath>    #include<cstdio>    #include<cstring>    #include<algorithm>    #define maxn 5010    #define ll long long    using namespace std;    struct node{    int to,f,m;    node*next,*rev;    }*con[maxn];    int dl[maxn],head,tail,de[maxn];    int n,a[maxn],s,t,v;    bool tag[maxn];    void addedge(int x,int y,int m)    {    node*p=new node;    p->to=y;        p->f=0;        p->m=m;        p->next=con[x];        con[x]=p;        p=new node;        p->to=x;        p->f=0;        p->m=0;        p->next=con[y];        con[y]=p;        con[x]->rev=con[y];        con[y]->rev=con[x];    }    bool bfs()    {        bool tmp=false;        head=1;tail=0;        dl[++tail]=s;        memset(de,0,sizeof(de));        de[s]=1;        while(head<=tail)        {            v=dl[head];        if(v==t) tmp=true;        for(node*p=con[v];p;p=p->next)        if(p->f<p->m&&de[p->to]==0)            dl[++tail]=p->to,de[p->to]=de[v]+1;        head++;        }        return tmp;    }    int dinic(int v,ll e)    {        ll o=0,temp=0;        if(v==t) return e;        if(tag[v]) return 0;        for(node*p=con[v];p;p=p->next)        {        if(de[p->to]==de[v]+1&&p->f<p->m)        {            o=dinic(p->to,min((int)e-(int)temp,(int)p->m-p->f));            temp+=o;            p->f+=o;            p->rev->f-=o;        }        if(temp==e) break;        }        if(temp==0) tag[v]=true;        return temp;    }    int f[maxn];    int ans1=0;    int main()    {        scanf("%d",&n);        for(int i=1;i<=n;++i)        scanf("%d",&a[i]);        for(int i=1;i<=n;++i) f[i]=1;        for(int i=1;i<=n;i++)        {            f[i]=1;            for(int j=1;j<i;j++)                if(a[j]<=a[i])f[i]=max(f[i],f[j]+1);            ans1=max(ans1,f[i]);        }        cout<<ans1<<endl;        s=0;t=2*n+1;        for(int i=1;i<=n;++i)        {        if(f[i]==1) addedge(s,i,1);        if(f[i]==ans1) addedge(i+n,t,1);        addedge(i,i+n,1);        }        for(int i=1;i<n;++i)        for(int j=i+1;j<=n;++j)        if(a[j]>=a[i]&&f[j]==f[i]+1) addedge(i+n,j,1);        ll ans2=0;        while(bfs())        {            memset(tag,0,sizeof(tag));            ans2+=dinic(s,0x3f3f3f3f);        }        cout<<ans2<<endl;        for(node*p=con[1];p;p=p->next)        if(p->to==n+1) p->m=0x3f3f3f3f;        for(node*p=con[n];p;p=p->next)        if(p->to==2*n) p->m=0x3f3f3f3f;        for(node*p=con[s];p;p=p->next)        if(p->to==1) p->m=0x3f3f3f3f;        for(node*p=con[2*n];p;p=p->next)        if(p->to==t) p->m=0x3f3f3f3f;        while(bfs())        {            memset(tag,0,sizeof(tag));            ans2+=dinic(s,0x3f3f3f3f);        }        cout<<ans2<<endl;    }