zoukankan      html  css  js  c++  java
  • CF10D LCIS

    洛咕

    POJ

    题意:求两个数列的最长公共上升子序列.输出长度和任意一种方案.

    这道题我真的做到崩溃,搞了几个小时,原本在洛咕上的方法在POJ上全WA了.个人认为是输出方案的问题.

    分析:设(f[i][j])表示(A)序列前i个和(B)序列前j个构成的最长公共上升子序列的长度.

    (A[i])不等于(B[j])时,(f[i][j]=f[i-1][j])

    (A[i]=B[j])时,(f[i][j]=max(f[i][j],f[i-1][t]+1)),t为最长公共上升子序列结尾的元素的位置.

    因为要输出方案,所以在每次更新序列时,再开一个数组记录一下,最后递归输出方案.

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int N=505;
    int a[N],b[N],f[N][N],g[N][N];
    inline void print(int n,int pos){
        if(!pos)return;
        print(n,g[n][pos]);
        printf("%d ",b[pos]);
    }
    int main(){
        int n=read();for(int i=1;i<=n;i++)a[i]=read();
        int m=read();for(int i=1;i<=m;i++)b[i]=read();
        for(int i=1,t=0;i<=n;i++,t=0)
        	for(int j=1;j<=m;j++){
    	    	f[i][j]=f[i-1][j];g[i][j]=g[i-1][j];
    	    	if(a[i]==b[j]&&f[i-1][t]+1>f[i][j]){
            		f[i][j]=f[i-1][t]+1;
            		g[i][j]=t;
    	    	}
    	    	if(a[i]>b[j]&&f[i-1][t]<f[i-1][j])t=j;
    		}
        int pos=0;
        for(int i=1;i<=m;i++)if(f[n][i]>f[n][pos])pos=i;
        printf("%d
    ",f[n][pos]);
        print(n,pos);puts("");
        return 0;
    }
    
    
    

    因为(f[i][j])都是由(f[i-1][j])转移而来的,所以可以滚掉第一维数组,优化空间.

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
       int s=0,w=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
       return s*w;
    }
    const int N=505;
    int a[N],b[N],f[N],g[N];
    inline void print(int pos){
        if(!pos)return;
        print(g[pos]);
        printf("%d ",b[pos]);
    }
    int main(){
        int n=read();for(int i=1;i<=n;i++)a[i]=read();
        int m=read();for(int i=1;i<=m;i++)b[i]=read();
        for(int i=1,t=0;i<=n;i++,t=0)
        	for(int j=1;j<=m;j++){
            	if(a[i]==b[j]&&f[t]+1>f[j]){
            		f[j]=f[t]+1;
            		g[j]=t;
            	}
            	if(a[i]>b[j]&&f[t]<f[j])t=j;
        	}
        int pos=0;
        for(int i=1;i<=m;i++)if(f[i]>f[pos])pos=i;
        printf("%d
    ",f[pos]);
        print(pos);puts("");
        return 0;
    }
    
    
    

    然后我又把递归输出方案改成了栈来实现,就在POJ上过了,真的好玄学啊.

    //#include<bits/stdc++.h>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int N=505;
    int a[N],b[N],st[N],f[N][N],g[N][N];
    int main(){
    		memset(g,-1,sizeof(g));
    		int n=read();for(int i=1;i<=n;i++)a[i]=read();
    		int m=read();for(int i=1;i<=m;i++)b[i]=read();
    		for(int i=1,t=0;i<=n;i++,t=0){
    	    	for(int j=1;j<=m;j++){
    				f[i][j]=f[i-1][j];
    					if(a[i]==b[j]&&f[i-1][t]+1>f[i][j]){
    		    		f[i][j]=f[i-1][t]+1;
    		    		g[i][j]=t;
    				}
    				if(a[i]>b[j]&&f[i-1][t]<f[i-1][j])t=j;
    	    	}
    		}
    		int pos=0;
    		for(int i=1;i<=m;i++)
    	    	if(f[n][i]>f[n][pos])pos=i;
    		printf("%d
    ",f[n][pos]);
    		if(f[n][pos]<=0)return 0;
    		int tmp=pos;
    		for(int i=n;i>=1;i--)
            	if(g[i][tmp]!=-1)
            		st[++st[0]]=a[i],tmp=g[i][tmp];
    		for(int i=st[0];i>=2;i--)printf("%d ",st[i]);
    		printf("%d 
    ",st[1]);
        return 0;
    }
    
  • 相关阅读:
    BZOJ 1101 莫比乌斯函数+分块
    BZOJ 2045 容斥原理
    BZOJ 4636 (动态开节点)线段树
    BZOJ 2005 容斥原理
    BZOJ 2190 欧拉函数
    BZOJ 2818 欧拉函数
    BZOJ 3123 主席树 启发式合并
    812. Largest Triangle Area
    805. Split Array With Same Average
    794. Valid Tic-Tac-Toe State
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10886066.html
Copyright © 2011-2022 走看看