[vijosP1303]导弹拦截(最长上升子序列转LCS)

描述

某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试验阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

格式

输入格式

输入数据只有一行,该行包含若干个数据,之间用半角逗号隔开,表示导弹依次飞来的高度(导弹最多有 20 枚,其高度为不大于 30000 的正整数)。

输出格式

输出数据只有一行,该行包含两个数据,之间用半角逗号隔开。第一个数据表示这套系统最多能拦截的导弹数;第二个数据表示若要拦截所有导弹至少要再添加多少套这样的系统。

样例1

样例输入1

389,207,155,300,299,170,158,65

样例输出1

   6,1





很明显这题首先需要求最长上升序列,这题有比较多的做法,我这里选用LCS(最长公共子序列)做法,但问题是最长公共子序列是求A={a1,a2,a3...an}与B={b1,b2,b3....bm}的最长公共子序列,这里只有一个序列串。

所以首先我们需要copy源串,然后对副本进行降序排序,得到一个序列,然后两个序列进行LCS就可以得出最长下降序列了。

然后回溯找出LCS中求出的串,对源串进行删除,最后递归执行直到源串为0就好了。

Java AC Code:
public class Main {
    //最长下降序列长度
    public static int m = 0;
    //还需要多少飞弹
    public static int need = 0;
    
    public static void main( String[] args ) {

        Scanner sc = new Scanner( System.in );
        while( sc.hasNext() ) {
            m=0;
            need=0;
            String str = sc.nextLine();
            int[] nums = getSplits( str, "," );
            List<Integer> list = new ArrayList<Integer>();
            for( int i = 0; i < nums.length; i++ ) {
                list.add( nums[ i ] );
            }
            LCS( nums,list );
            System.out.println( m+","+(need-1) );
        }
    }
    //进行LCS
    public static void LCS( int[] nums, List<Integer> list ) {
        int[] sortNums = new int[ nums.length ];
        int[][] b = new int[ nums.length + 1 ][ nums.length + 1 ];
        int n = nums.length;
        for( int i = 0; i < n; i++ ) {
            sortNums[ i ] = nums[ i ];
        }
        Arrays.sort( sortNums );
        int[] descNums = new int[ n ];
        for( int i = 0; i < n; i++ ) {
            descNums[ i ] = sortNums[ n - i - 1 ];
        }
        int[][] lcs = new int[ n + 1 ][ n + 1 ];
        for( int i = 1; i <= n; i++ ) {
            for( int j = 1; j <= n; j++ ) {
                if( nums[ i - 1 ] == descNums[ j - 1 ] ) {
                    lcs[ i ][ j ] = lcs[ i - 1 ][ j - 1 ] + 1;
                    b[ i ][ j ] = 0;
                } else {
                    if( lcs[ i - 1 ][ j ] > lcs[ i ][ j - 1 ] ) {
                        lcs[ i ][ j ] = lcs[ i - 1 ][ j ];
                        b[ i ][ j ] = -1;
                    } else {
                        lcs[ i ][ j ] = lcs[ i ][ j - 1 ];
                        b[ i ][ j ] = 1;
                    }
                }
            }
        }
        
        
        //递归求need,并且判断获取最长的下降序列。
        m = lcs[n][n] > m?lcs[n][n]:m;
        while(list.size() !=0){
            printLCS( b, nums, n, n, list );
            int[] newNums = new int[list.size()];
            for(int i=0;i<list.size();i++){
                newNums[i] = list.get( i);
            }
            LCS(newNums,list);
            need++;
        }
    }
   
    
    //输入分片
    public static int[] getSplits( String str, String pattern ) {
        String[] splits = str.split( pattern );
        int[] ret = new int[ splits.length ];
        for( int i = 0; i < ret.length; i++ ) {
            ret[ i ] = Integer.parseInt( String.valueOf( splits[ i ] ) );
        }
        return ret;
    }
    //回溯输出最长序列。
    public static void printLCS( int[][] b, int[] nums, int i, int j,List<Integer> list) {
        if( i == 0 || j == 0 )
            return;
        else if( b[ i ][ j ] == 0 ) {
            printLCS( b, nums, i - 1, j - 1,list );
            list.remove( new Integer(nums[i-1]) );
        } else if( b[ i ][ j ] == -1 ) {
            printLCS( b, nums, i - 1, j,list );
        } else {
            printLCS( b, nums, i, j - 1,list);
        }
    }
}

关于LCS算法的具体实现,自行百度啦,主要就是进行矩阵Dp,判断相等于不相等时候的选择大小。

 










posted @ 2016-05-04 14:34  hudiwei-hdw  阅读(250)  评论(0编辑  收藏  举报