美文网首页
洛谷(最长不下降子序列问题)

洛谷(最长不下降子序列问题)

作者: kimoyami | 来源:发表于2018-10-02 17:52 被阅读57次

    链接:https://www.luogu.org/problemnew/show/P2766
    思路:首先第一问用n^2的dp求出,第二问用网络流做,因为每个点只能用一次相当于结点上有限制,所以需要拆点,左边的点负责接输入,右边的点负责输出,中间拉一条容量为1的边,然后源点到每个dp[i] = 1的点都拉一条边,表示开始,所有dp[i] = res(一问答案)的点到汇点拉一条边,表示结束,跑一遍网络流即可。第三问不能重新建图会超时,直接把源点到1的边变为无穷,1拆的两个点之间的边变为无穷,n如果跟汇点有边就把边变为无穷,n拆的两个点间变为无穷,跑的最大流加上第二问的答案就是第三问的答案。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1010;
    const int INF  = 1e9;
    int n;
    int a[maxn];
    
    struct edge{
        int from,to,cap,flow;
    };
    
    struct Dinic{
        int n,m,s,t;
        vector<int> G[maxn];
        vector<edge> edges;
        int d[maxn];
        int cur[maxn];
        bool vis[maxn];
    
        void init(int n){
            this->n = n;
            for(int i=0;i<=n;i++)G[i].clear();
            edges.clear();
        }
    
        void addedge(int from,int to,int cap){
            edges.push_back(edge{from,to,cap,0});
            edges.push_back(edge{to,from,0,0});
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool bfs(){
            memset(vis,0,sizeof(vis));
            d[s] = 0;
            vis[s] = 1;
            queue<int> q;
            q.push(s);
            while(!q.empty()){
                int x = q.front();
                q.pop();
                for(int i=0;i<G[x].size();i++){
                    edge &e = edges[G[x][i]];
                    if(!vis[e.to]&&e.cap>e.flow){
                        vis[e.to] = 1;
                        d[e.to] = d[x] + 1;
                        q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int dfs(int x,int a){
            if(x==t||a==0)return a;
            int flow = 0,f;
            for(int &i = cur[x];i<G[x].size();i++){
                edge &e = edges[G[x][i]];
                if(d[x] + 1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
                    e.flow+=f;
                    edges[G[x][i]^1].flow-=f;
                    flow+=f;
                    a-=f;
                    if(!a)break;
                }
            }
            return flow;
        }
    
        int maxflow(int s,int t){
            this->s = s;
            this->t = t;
            int flow = 0;
            while(bfs()){
                memset(cur,0,sizeof(cur));
                flow+=dfs(s,INF);
            }
            return flow;
        }
    }solver;
    
    int dp[maxn];
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++)dp[i] = 1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
               if(a[j]<=a[i])dp[i] = max(dp[i],dp[j] + 1);
        }
        }
        int res = 0;
        for(int i=1;i<=n;i++){
            res = max(res,dp[i]);
        }
    
        solver.init(2*n+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                if(a[j]<=a[i]&&dp[j]+1==dp[i])//一定要两个条件都确保才能建边
    solver.addedge(j+n,i,1);
            }
        }
        for(int i=1;i<=n;i++){
            solver.addedge(i,i+n,1);
            if(dp[i]==res){
                solver.addedge(i+n,2*n+1,1);
            }
            if(dp[i]==1)solver.addedge(0,i,1);
        }
        int res1 = solver.maxflow(0,2*n+1);
    
        solver.addedge(0,1,INF);
        solver.addedge(1,1+n,INF);
        if(dp[n]==res){//如果有边则加一条容量为无穷的边
            solver.addedge(n,2*n,INF);
            solver.addedge(2*n,2*n+1,INF);
        }
        int res2 = res1 + solver.maxflow(0,2*n+1);
        printf("%d\n%d\n%d\n",res,res1,res2);
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:洛谷(最长不下降子序列问题)

          本文链接:https://www.haomeiwen.com/subject/wuraoftx.html