zoukankan      html  css  js  c++  java
  • poj1692

    题意:两个数列,第一行的数字可以和第二行的数字连线。连线有如下条件,被连上的两数字必须相等,且每个数字只能连一条线,每条连线必须与且仅与另一条连线相交,相交两连线上的数字不能相等。问最多能连多少条线。

    分析:dp。f[i][j]表示第一行的前i个数字和第二行的前j个数字最多能连几条线,则f[i][j]=max(f[i-1][j],f[i][j-1],f[k-1][l-1]+2)。k是第一行前i-1个数字中最右一个能与第二行j位置连线的数的位置。l同理。这样状态转移为n,状态为n^2,总的时间复杂度为n^3。但是我们可以不用每次顺序查找k,l的值,我们进行预处理。数组last_equal1[i][x]表示第一行前i个数字中最右一个等于x的数字的位置。题中说x的取值范围在100以内,所以空间上是可行的。若第一行第i个数恰好是x那么last_equal1[i][x]=i,否则last_equal1[i][x]=last_equal1[i-1][x]。last_equal2[j][x]同理。这样总复杂度降为n^2。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    #define maxn 105
    
    int n, m;
    int f[maxn][maxn];
    int last_equal1[maxn][maxn], last_equal2[maxn][maxn];
    int chain1[maxn], chain2[maxn];
    
    void input()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &chain1[i]);
        for (int i = 1; i <= m; i++)
            scanf("%d", &chain2[i]);
    }
    
    void make(int n, int chain[], int last_equal[][maxn])
    {
        memset(last_equal, 0, sizeof(last_equal));
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= 100; j++)
                if (chain[i] == j)
                    last_equal[i][j] = i;
                else
                    last_equal[i][j] = last_equal[i - 1][j];
    }
    
    int work()
    {
        make(n, chain1, last_equal1);
        make(m, chain2, last_equal2);
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
                int a = chain1[i];
                int b = chain2[j];
                int pos1 = last_equal1[i][b];
                int pos2 = last_equal2[j][a];
                if (a != b && pos1 != 0 && pos2 != 0)
                    f[i][j] = max(f[i][j], f[pos1 - 1][pos2 - 1] + 1);
            }
        return f[n][m] * 2;
    }
    
    int main()
    {
        //freopen("t.txt", "r", stdin);
        int t;
        scanf("%d", &t);
        while (t--)
        {
            input();
            printf("%d\n", work());
        }
        return 0;
    }
  • 相关阅读:
    有关敏捷(1)
    有关创业的想法
    2010必须做到的事
    技术搜索还是谷歌强
    错误处理的一些想法
    定期自动删除数据
    ip
    asp.ent Repeter实现分页
    QQ客服在线聊天
    几种文件上传的方法
  • 原文地址:https://www.cnblogs.com/rainydays/p/2961436.html
Copyright © 2011-2022 走看看