zoukankan      html  css  js  c++  java
  • UVa 10131 Is Bigger Smarter? 最长公共子序列 yongmou

    题意:给出不超过1000头大象的(重量,IQ),其中重量之间可能有相同的,IQ之间也可能有相同的,寻找重量严格递增,IQ严格递减的序列,输出其长度,和序列,序列以输入数据中的序号表示。

    思路:第一步:对这些大象按照重量排序,排序时,只对索引排序就可以了,不需要动大象的实际数据,比如(600,300,400),对应索引是(1, 2,3)排序后是(2, 3,1)。

       第二步:对IQ排序,这需要消去重复的。 我记得,见过一个算法题,如何对于0到n的若干整数以O(n)的时间排序?我的解答是:用一个数组appear[n],初始化为0,若数字m出现则appear[m]++,最后一个循环拷贝到一个数组中。并且这样做的,可以很容易消去重复的。

         第三步:对上述两个序列求最长公共子序列。子问题填表。回溯找到最优解。

       最后:消去序列中重量重复的,输出。

    代码:

    #include<cstdio>
    #include
    <algorithm>
    using namespace std;

    #define MAX 1000

    struct elephant{
    int w;
    int s;
    };

    int n, m;
    elephant elephants[MAX
    +1];
    int a[MAX+1]; //索引
    int b[MAX+1]; //大象IQ的降序排列
    bool appear[10000+1]; //用于对大象IQ排序, 若出现了IQ为i的大象则in[i]置true
    int sub[MAX+1], len;//子序列,长度

    int dp[MAX+1][MAX+1];
    char sel[MAX+1][MAX+1]; //dp时选择, 1表示相等,2左, 3上

    //用于对重量排序的函数对象
    struct cmp{
    bool operator ()(int a, int b){
    return (elephants[a].w < elephants[b].w);
    }
    };

    //最长公共子序列
    void LCS(){
    int i, j;
    for(i=0; i<=n; ++i)
    dp[i][
    0] = 0;
    for(j=0; j<=m; ++j)
    dp[
    0][j] = 0;
    for(i=1; i<=n; ++i)
    for(j=1; j<=m; ++j){
    if(elephants[a[i]].s == b[j]){
    dp[i][j]
    = dp[i-1][j-1] + 1;
    sel[i][j]
    = 1;
    }
    else if(dp[i-1][j] <= dp[i][j-1]){
    dp[i][j]
    = dp[i][j-1];
    sel[i][j]
    = 2;
    }
    else{
    dp[i][j]
    = dp[i-1][j];
    sel[i][j]
    = 3;
    }
    }
    }

    //回溯找到公共子序列
    void backtrace(){
    len
    = 0;
    int i, j;
    i
    =n, j=m;
    while(i!=0 && j!=0){
    if(sel[i][j] == 1){
    ++len;
    sub[len]
    = a[i];
    --i, --j;
    }
    else if(sel[i][j] == 2)
    --j;
    else
    --i;
    }
    }

    int main(){
    // freopen("in", "r", stdin);
    int w, s;
    n
    =0;
    while(scanf("%d %d", &w, &s) != EOF){
    ++n;

    elephants[n].w
    = w;
    elephants[n].s
    = s;
    appear[s]
    = true;
    a[n]
    = n;
    }
    sort(a
    +1, a+1+n, cmp());

    m
    = 0;
    for(int i=10000; i>=1; --i){
    if(appear[i]){
    m
    ++;
    b[m]
    = i;
    }
    }
    LCS();
    backtrace();

    //消去重量相同的
    int k, j;
    k
    =1;
    b[
    1] = sub[len];
    for(j=len-1; j>=1; --j){
    if(elephants[sub[j]].w == elephants[b[k]].w)
    --len;
    else{
    ++k;
    b[k]
    = sub[j];
    }
    }
    printf(
    "%d\n", len);
    for(k=1; k<=len; ++k)
    printf(
    "%d\n", b[k]);

    return 0;
    }
  • 相关阅读:
    回溯算法总结
    第四章总结
    第四章编程总结
    动态规划总结:
    第三章实践心得
    分治算法体会
    第二章上机实践总结
    代码规范与《数学之美》读后感
    第二次c++作业
    第一次博客作业
  • 原文地址:https://www.cnblogs.com/liyongmou/p/1774739.html
Copyright © 2011-2022 走看看