「网络流 24 题」最长递增子序列

题目链接

算法:

          对于第一问,设f[i]为以i这个位置为结尾的最长递增子序列的长度,一个O(n^2)的DP即可;

          对于第二问,因为每个位置仅能选一次,我们可以把一个位置i拆成两个节点i1与i2,每一个i1各向对应的i2连一条无限流量的边,源点S向每一个f[i]=1的i的i1连一条流量为1的边,再由每一个f[i]=第一问答案的节点i的i2向汇点T连一条流量为1的边,最后对于每一组满足f[i]=f[j]+1且co[i]>=co[j]的i与j,由节点i2向j1连一条流量为1的边。求网络最大流即可。

          对于第三问,我们在第二问的边的基础上,把S流向i1的边、i1流向i2的边、n1流向n2的边的流量都改为无限,最后如果存在n2流向T的边的话,也把该边的流量改为无限。求网络最大流即可。

          (具体细节参考程序)

Code:

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
    char c=getchar();num=0;T f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
    num*=f;
}
template<typename T> void qwq(T x){
    if(x>9)qwq(x/10);
    putchar(x%10+'0');
}
template<typename T> void write(T x){
    if(x<0){x=-x;putchar('-');}
    qwq(x);putchar('\n');
}
template<typename T> void chkmax(T &x,T y){x=x>y?x:y;}
int s,t;
int co[510];int f[510];
struct wzy{
    int nxt,vertice,w;
}edge[300010];
int head[1010];int len=1;
inline void add_edge(int x,int y,int z){
    edge[++len].nxt=head[x];edge[len].vertice=y;
    edge[len].w=z;head[x]=len;return;
}

int d[1010];queue<int>v;
inline bool bfs(){
    memset(d,0,sizeof(d));
    while(!v.empty())v.pop();
    v.push(s);d[s]=1;
    while(!v.empty()){
        int nop=v.front();v.pop();
        for(int i=head[nop];i;i=edge[i].nxt){
            int temp=edge[i].vertice;
            if(edge[i].w&&!d[temp]){
                v.push(temp);d[temp]=d[nop]+1;
                if(temp==t)return 1;
            }
        }
    } 
    return 0;
}
inline int dinic(int now,int val){
    if(now==t)return val;
    int k=0;
    for(int i=head[now];i&&val!=k;i=edge[i].nxt){
        int nop=edge[i].vertice;
        if(!edge[i].w||d[nop]!=d[now]+1)continue;
        int temp=dinic(nop,min(val-k,edge[i].w));
        edge[i].w-=temp;edge[i^1].w+=temp;k+=temp;
    }
    return k;
}

int main(){
    int n;read(n);
    rep(i,1,n){read(co[i]);}
    int ans1,ans2;ans1=ans2=0;
    s=0;t=2*n+1;
    if(n==1&&co[1]==1){
    	write(1);write(1);write(1);return 0;
	}
    
    f[1]=1;ans1=1;
    rep(i,2,n){
        f[i]=1;
        rep(j,1,i-1){if(co[i]>=co[j]){chkmax(f[i],f[j]+1);}}
        chkmax(ans1,f[i]);
    }
    write(ans1);
    
    rep(i,1,n){if(f[i]==1){add_edge(s,2*i-1,1);add_edge(2*i-1,s,0);}} 
    rep(i,1,n){add_edge(2*i-1,2*i,1);add_edge(2*i,2*i-1,0);}
    rep(i,1,n){if(f[i]==ans1){add_edge(2*i,t,1);add_edge(t,2*i,0);}} 
    rep(i,1,n){
        rep(j,1,i-1){
            if(f[i]==f[j]+1&&co[i]>=co[j]){add_edge(2*j,2*i-1,1);add_edge(2*i-1,2*j,0);}
        }
    }
    int flow=0;
    while(bfs()){
        do{
            flow=dinic(s,INT_MAX);ans2+=flow;
        }while(flow);
    }
    write(ans2);
    
    add_edge(s,1,INT_MAX);add_edge(1,2,INT_MAX);add_edge(2*n-1,2*n,INT_MAX);
    if(f[n]==ans1){add_edge(2*n,t,INT_MAX);}
    flow=0;
    while(bfs()){
        do{
            flow=dinic(s,INT_MAX);ans2+=flow;
        }while(flow);
    }
    write(ans2);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Bill_Benation/article/details/86807981