最长不下降子序列问题

乍一看好像是个DP,做着做着发现锅了……

好吧,试试WLL。

首先用dp求出最长不下降子序列的长度(简单不再赘述)

问题2:

超级源点与所有f[i]=0的点的入口相连,边权为1。

超级汇点与所有f[i]=ans的点的出口相连,边权为inf。

连所有的边满足i<j,a[i]<=a[j],f[i]=f[j]-1,边权为inf。

连每个点的入口和出口,边权为1.

(这简直是套路……)

问题3:

将1和n的出入口边权改为inf,将超级源点到1的边权改为inf

几个小细节:

1.ans=1时输出:1,n,n

2.重建图时边数清零,beg赋值为-1

搞定,看代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4;
const int maxm=1e5;
int n,a[maxn],f[maxn];
int beg[maxn],nex[maxm],to[maxm],w[maxm],e;
inline void add(int x,int y,int z){
    nex[e]=beg[x];beg[x]=e;
    to[e]=y;w[e]=z;e++;
}
int dep[maxn];
queue<int>q;
inline int bfs(){
    memset(dep,0x3f,sizeof(dep));
    while(!q.empty())q.pop();
    q.push(0);
    dep[0]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=beg[x];~i;i=nex[i]){
            int t=to[i];
            if(w[i]&&dep[t]>3*n){
                dep[t]=dep[x]+1;
                q.push(t);
            }
        }
    }
    return dep[2*n+1]<3*n;
}
inline int dfs(int x,int lim){
    if(x==2*n+1||!lim)return lim;
    int ans=0;
    for(int i=beg[x];~i;i=nex[i]){
        int t=to[i];
        if(dep[t]==dep[x]+1){
            int flow=dfs(t,min(lim,w[i]));
            ans+=flow;
            lim-=flow;
            w[i]-=flow;
            w[i^1]+=flow;
        }
    }
    return ans;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++){
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[i]>=a[j])f[i]=max(f[i],f[j]+1);
    }
    int ans=0,tot=0,res=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,f[i]);
    if(ans==1){
        printf("1
%d
%d
",n,n);
        return 0;
    }
    printf("%d
",ans);
    memset(beg,-1,sizeof(beg));
    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){
                add(i+n,j,1e9);
                add(j,i+n,0);
            }
    for(int i=1;i<=n;i++)
        add(i,i+n,1),add(i+n,i,0);
    for(int i=1;i<=n;i++)
        if(f[i]==1)add(0,i,1e9),add(i,0,0);
    for(int i=1;i<=n;i++)
        if(f[i]==ans)add(i+n,2*n+1,1e9),add(2*n+1,i+n,0);
    while(bfs())tot+=dfs(0,1e9);
    printf("%d
",tot);
    e=0;
    memset(beg,-1,sizeof(beg));
    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){
                if(i==1&&j==n){
                    add(i+n,j,1);
                    add(j,i+n,0);
                }else{
                    add(i+n,j,1e9);
                    add(j,i+n,0);
                }
            }
    add(1,n+1,1e9),add(n+1,1,0);
    add(n,2*n,1e9),add(2*n,n,0);
    for(int i=2;i<n;i++)
        add(i,i+n,1),add(i+n,i,0);
    add(0,1,1e9),add(1,0,0);
    for(int i=2;i<n;i++)
        if(f[i]==1)add(0,i,1),add(i,0,0);
    for(int i=1;i<=n;i++)
        if(f[i]==ans)add(i+n,2*n+1,1e9),add(2*n+1,i+n,0);
    while(bfs())res+=dfs(0,1e9);
    printf("%d
",res);
    return 0;
}

深深地感到自己的弱小。

原文地址:https://www.cnblogs.com/syzf2222/p/12378007.html