HDU 5406 DP topo序

HDU 5406

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5406

题意:

给一堆苹果,每个苹果有重量和价值。两个人取苹果,对于一个人,只能取一个苹果j,相比上次取得苹果,j的重量要小,价值要大。

问最后两个人取的最多的苹果数量是多少。

思路:

感谢http://blog.csdn.net/l_ecry/article/details/47830927

先写解题思路,看懂的~

初始想法是dp,但是发现有两个人无法处理。实际上有两个人的时候通常设dp[i][j],分别表示第一个人状态为i,第二个人状态为j

本题也是如此,设dp[i][j]为第一个人在i点,第二个人在j点时的最大值。

下面要决定如何去dp,也就是dp的顺序。

题解采取topodp。按照不同高度高的在前面、相同高度D值小的在前面排序后,建立topo图。然后在图上,如果当前点id值比后面点jd值小,则ij连一条边。

然而这样是会TLE的。

于是原作者加了两个个剪枝。

剪枝一:若当前jd值和已经遍历到并且与i相连点的最小d值要大,则不在ij之间连边。简单证明:假设当前点为j2d值为d2,而已经遍历到d值最小的点j1dd1。若d1 < d2,则在遍历到j1时,j2肯定会与j1连一条边,这样得出来的结果肯定比i直接与j2相连要大。证毕。

剪枝二:假设第一个人站的点i<=第二个人站的点j,这样能减少很多无效转移。

 

第一次做非数组顺序的dp题,感觉关键是原数组顺序和dp顺序之间的转换,具体就是开两个数组互相指针指一指。

 

简直就是照着抄了一遍

 

源码:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <cstdlib>

#include <algorithm>

#include <iostream>

#include <queue>

#include <vector>

using namespace std;

#define inf (1000000050)

#define gmax(a,b) ((a) > (b) ? (a) : (b))

const int MAXN = 1000 + 50;

int dp[MAXN][MAXN], n;

vector<int>lin[MAXN];

struct Lv

{

    int h, d;

}lv[MAXN];

bool cmp(Lv a, Lv b)

{

    if(a.h == b.h)  return a.d < b.d;

    return a.h > b.h;

}

int q[MAXN], id[MAXN], tail;

int in[MAXN];

void topo()

{

    memset(in, 0, sizeof(in));

    tail = 0;

    q[tail++] = 0;

    id[0] = 0;

    for(int i = 1 ; i <= n ; i++){

        lin[0].push_back(i);

        in[i]++;

        for(int j = i + 1 ; j <= n ; j++){

            if(lv[j].d >= lv[i].d){

                lin[i].push_back(j);

                in[j]++;

            }

        }

        in[n + 1]++;

        lin[i].push_back(n + 1);

    }

    for(int i = 0 ; i < tail ; i++){

        for(int j = 0 ; j < (int)lin[i].size() ; j++){

            int v = lin[i][j];

            in[v]--;

            if(in[v] == 0){

                q[tail++] = v;

                id[v] = tail - 1;

            }

        }

    }

}

void DP()

{

    for(int i = 0 ; i <= n + 1 ; i++)

        for(int j = 0 ; j <= n + 1 ; j++)

            dp[i][j] = -inf;

    dp[0][0] = 0;

    for(int i = 0 ; i <= n + 1 ; i++){

        for(int j = i ; j <= n + 1 ; j++){

            if(dp[i][j] < 0)

                continue;

            int u = q[i];

            for(int k = 0 ; k < (int)lin[u].size() ; k++){

                int x = id[lin[u][k]];

                if(x == j)

                    dp[x][j] = gmax(dp[x][j], dp[i][j]);

                else if(x < j)

                    dp[x][j] = gmax(dp[x][j], dp[i][j] + 1);

                else if(x > j)

                    dp[j][x] = gmax(dp[j][x], dp[i][j] + 1);

            }

        }

    }

}

int main()

{

    int t;

    scanf("%d", &t);

    while(t--){

        scanf("%d", &n);

        for(int i = 1 ; i <= n ; i++)

            scanf("%d%d", &lv[i].h, &lv[i].d);

        sort(lv + 1, lv + n + 1, cmp);

        for(int i = 0 ; i <= n + 1 ; i++)

            lin[i].clear();

        lv[0].h = 0, lv[0].d = 0;

        lv[n+1].h = inf, lv[n+1].d = inf;

        topo();

        for(int i = 0 ; i <= n + 1 ; i++)

            lin[i].clear();

        for(int i = n ; i >= 0; i--){

            int mm = inf + 5;

            for(int j = i + 1 ; j <= n + 1 ; j++){

                if(mm <= lv[j].d)

                    continue;

//                if(i == 4)

//                    printf("j = %d, mm = %d, lv[j].d = %d\n", j, mm, lv[j].d);

                if(lv[i].d <= lv[j].d){

                    lin[i].push_back(j);

                    mm = min(mm, lv[j].d);

                }

            }

        }

//        printf("lin\n");

//        for(int i = 0 ; i <= n ; i++){

//            printf("i = %d, h = %d, d = %d, j =  ", i, lv[i].h, lv[i].d);

//            for(int k = 0 ; k < (int)lin[i].size() ; k++)

//                printf("%d ", lin[i][k]);

//            printf("\n");

//        }

        DP();

//        printf("dp\n");

//        for(int i = 0 ; i <= n + 1; i++){

//            for(int j = 0 ; j <= n + 1 ; j++)

//                printf("%11d ", dp[i][j]);

//            printf("\n");

//        }

        printf("%d\n", dp[n+1][n+1] - 1);

    }

    return 0;

}

 

 

你可能感兴趣的:(HDU 5406 DP topo序)