zoukankan      html  css  js  c++  java
  • 最长不下降子序列问题

    题目描述

    题解:

    最大费用流。

    每个点向后面不小于它的点建一条容量为$1$,费用$-1$的边。

    $S$向所有点建容量为$1$的入边(费用为$-1$),所有点向$T$建容量为$1$的出边(费用为$0$)。

    然后最大费用流。

    由于第一次得到的通路是费用最小的,这个费用的相反数就是问题一的答案。

    然后继续跑,跑出几个最小费用,问题二的答案就加几。

    第三问只要重新建图,然后$S$只向$1$,只有$n$向$T$,容量正无穷。

    代码:

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 1050
    const int inf = 0x3f3f3f3f;
    inline int rd()
    {
        int f=1,c=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
        return f*c;
    }
    int n,m,S,T,hed[N],cnt=-1,a[N];
    struct EG
    {
        int to,nxt,w,c;
    }e[4*N*N];
    void ae(int f,int t,int w,int c)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        e[cnt].w = w;
        e[cnt].c = c;
        hed[f] = cnt;
    }
    void AE(int f,int t,int w,int c)
    {
        ae(f,t,w,c);
        ae(t,f,0,-c);
    }
    int dep[N],fl[N];
    int pre[N],fa[N];
    bool vis[N];
    queue<int>q;
    bool spfa()
    {
        memset(dep,0x3f,sizeof(dep));
        dep[S]=0,fl[S]=inf,vis[S]=1;q.push(S);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int j=hed[u];~j;j=e[j].nxt)
            {
                int to = e[j].to;
                if(e[j].w&&dep[to]>dep[u]+e[j].c)
                {
                    dep[to] = dep[u]+e[j].c;
                    fl[to] = min(fl[u],e[j].w);
                    pre[to] = j,fa[to] = u;
                    if(!vis[to])
                    {
                        vis[to] = 1;
                        q.push(to);
                    }
                }
            }
            vis[u] = 0;
        }
        return dep[T] != inf;
    }
    void mcmf(bool typ)
    {
        int ct = 0;
        bool fd = 0;
        while(spfa())
        {
            if(!fd)m = fl[T]*dep[T],fd=1;
            if(fl[T]*dep[T]==m)ct++;
            else break;
            int u = T;
            while(u!=S)
            {
                e[pre[u]].w-=fl[T];
                e[pre[u]^1].w+=fl[T];
                u = fa[u];
            }
        }
        if(!typ)
        {
            printf("%d
    %d
    ",-m,ct);
        }else
        {
            printf("%d
    ",ct);
        }
    }
    void sol1()
    {
        memset(hed,-1,sizeof(hed));
        for(int i=1;i<=n;i++)
        {
            AE(S,i<<1,1,-1);
            AE(i<<1|1,T,1,0);
            AE(i<<1,i<<1|1,1,0);
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(a[j]>=a[i])
                    AE(i<<1|1,j<<1,1,-1);
        mcmf(0);
    }
    void sol2()
    {
        memset(hed,-1,sizeof(hed));
        for(int i=2;i<n;i++)
        {
            AE(S,i<<1,1,-1);
            AE(i<<1|1,T,1,0);
            AE(i<<1,i<<1|1,1,0);
        }
        AE(S,2,inf,-1);
        AE(2,3,inf,0);
        AE(3,T,1,0);
        AE(S,n<<1,1,-1);
        AE(n<<1,n<<1|1,inf,0);
        AE(n<<1|1,T,inf,0);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(a[j]>=a[i])
                    AE(i<<1|1,j<<1,1,-1);
        mcmf(1);
    }
    int main()
    {
        n = rd();S = 0,T = 1;
        for(int i=1;i<=n;i++)a[i] = rd();
        sol1();
        sol2();
        return 0;
    }
  • 相关阅读:
    与生命晒跑
    关于你有一条未读短信的静态单页
    【微收藏】来自Twitter的自动文字补齐jQuery插件
    chrome 插件个人使用推介
    vscode中检测代码中的空白行并去除的方法
    FTP文件乱码导致的无法删除
    git操作遇到的几个问题
    一个srand、rand结果相同的问题
    【verilog】单周期MIPS CPU设计
    【verilog】多周期MIPS CPU设计
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10256687.html
Copyright © 2011-2022 走看看