zoukankan      html  css  js  c++  java
  • P2766 [网络流24题]最长不下降子序列问题

    ha~

    «问题描述:

    给定正整数序列$x_1,...,x_n$ 。$n<=500$

    求(1)计算其最长不下降子序列的长度$s$。

    (2)计算从给定的序列中最多可取出多少个长度为$s$的不下降子序列。

    (3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列。


    (1)暴力n方解决

    (2)建分层图,把图每个顶点i按照F[i]的不同分为若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长不下降子序列。由 S 向所有$ f_i = 1$ 的$ i $连容量为$ 1 $的边,由 所有$ f_i = s $的$ i $向$ T $连容量为$ 1$ 的边。对于所有的$ (i,j)$,若$ i < j,f_i +1 = f_j$,则由$ i$ 向$ j$ 连容量为 $1$ 的边。这样一来,所 有从 $S$ 出发到达$ T$ 的的路径都是一个长度为 $s $的上升子序 列。

    注意拆点,以保证同一个数不会重复使用。一个连入边,一个连出边,两个点 之间连流量为 1 的限制边。

    注意事项: line49的条件判断注意$f[j]+1==f[i]$的前提是要$a[j]<=a[i]$才可以连边!

    (3)把之前的边的流量限制改一下即可,对1号和n号微调后原样跑。

    注意事项(其实网上绝大部分题解好像都忽略了):建边时s向1号点的容量不可为无穷,应设为n,  n号点连t同理.

    比如这个毒瘤数据

    1

    1

    绝大部分题解输的是INF,但其实是1

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 typedef pair<int,int> pii;
     5 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
     6 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
     7 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
     8 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
     9 template<typename T>inline T read(T&x){
    10     x=0;char c;while(!isdigit(c=getchar()))if(isalpha(c))return x=(int)c;
    11     while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x;
    12 }
    13 const int N=500+7,M=150000+7,INF=0x3f3f3f3f;
    14 int w[2][M<<1],v[2][M<<1],Next[2][M<<1],Head[2][N<<1],cur[2][N<<1],dis[2][N<<1],tot[2],s,t,n;
    15 inline void Addedge(int x,int y,int z,int p){
    16     v[p][++tot[p]]=y,Next[p][tot[p]]=Head[p][x],Head[p][x]=tot[p],w[p][tot[p]]=z;
    17     v[p][++tot[p]]=x,Next[p][tot[p]]=Head[p][y],Head[p][y]=tot[p],w[p][tot[p]]=0;
    18 }
    19 #define y v[p][j]
    20 inline char bfs(int p){
    21     queue<int> q;q.push(s),memset(dis[p],0,sizeof dis[p]),dis[p][s]=1;
    22     for(register int i=1;i<=(n<<1)+2;++i)cur[p][i]=Head[p][i];
    23     while(!q.empty()){
    24         int x=q.front();q.pop();
    25         for(register int j=Head[p][x];j;j=Next[p][j])if(w[p][j]&&!dis[p][y]){
    26             dis[p][y]=dis[p][x]+1,q.push(y);
    27             if(y==t)return 1;
    28         }
    29     }
    30     return 0;
    31 }
    32 int dinic(int x,int flow,int p){
    33     if(!flow||x==t)return flow;
    34     int rest=flow,k;
    35     for(register int j=cur[p][x];j&&rest;cur[p][x]=j,j=Next[p][j])if(w[p][j]&&dis[p][y]==dis[p][x]+1){
    36         if(!(k=dinic(y,_min(rest,w[p][j]),p)))dis[p][y]=0;
    37         rest-=k,w[p][j]-=k,w[p][j^1]+=k;
    38     }
    39     return flow-rest;
    40 }
    41 #undef y
    42 int a[N],f[N],ans,maxflow;
    43 
    44 int main(){//freopen("P2766.in","r",stdin);//freopen("P2766.txt","w",stdout);
    45     read(n);s=(n<<1)+1,t=s+1,tot[0]=tot[1]=1;
    46     for(register int i=1;i<=n;++i){
    47         read(a[i]);f[i]=1;
    48         for(register int j=1;j<i;++j)if(a[j]<=a[i])MAX(f[i],f[j]+1);
    49         for(register int j=1;j<i;++j)if(f[j]+1==f[i]&&a[j]<=a[i])Addedge(j+n,i,1,0),Addedge(j+n,i,1,1);
    50         MAX(ans,f[i]),Addedge(i,i+n,1,0);if(f[i]==1)Addedge(s,i,1,0),i==1?Addedge(s,i,n,1):Addedge(s,i,1,1);
    51         if(i==1||i==n)Addedge(i,i+n,n,1);else Addedge(i,i+n,1,1);
    52     }
    53     printf("%d
    ",ans);
    54     for(register int i=1;i<=n;++i)if(f[i]==ans)Addedge(i+n,t,1,0),i==n?Addedge(i+n,t,n,1):Addedge(i+n,t,1,1);
    55     while(bfs(0))maxflow+=dinic(s,n,0);
    56     printf("%d
    ",maxflow);maxflow=0;
    57     while(bfs(1))maxflow+=dinic(s,n,1);
    58     printf("%d
    ",maxflow);
    59     return 0;
    60 }
  • 相关阅读:
    7大python 深度学习框架的描述及优缺点绍
    nodejs 和 js
    python操redis
    python ConfigParser 的小技巧
    RHEL 7.3修改网卡命名规则为ethX
    redhat7.3配置163 yum源
    分区脚本(fdisk)
    linux之sed用法
    linux awk命令详解
    Python 装饰器学习
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10357439.html
Copyright © 2011-2022 走看看