UVa 103 Stacking Boxes --- DAG上的动态规划

  

  UVa 103

  题目大意:给定n个箱子,每个箱子有m个维度,

       一个箱子可以嵌套在另一个箱子中当且仅当该箱子的所有的维度大小全部小于另一个箱子的相应维度,

       (注意箱子可以旋转,即箱子维度可以互换),求最多能套几个箱子。

       第一行输入为n,m,之后是n行m维的箱子

  解题思路:嵌套关系是二元关系,因此这题即在DAG上做动态规划,

       只不过将二维的判断改成了n维,其他不变。

       详细看考:DAG上的动态规划之嵌套矩形  (ps:这题可以理解成嵌套m边形)

/* UVa 103 Stacking Boxes --- DAG上的动态规划 */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n, m;    //n为结点数,m为维度(n <= 30, m <= 10)
int G[35][35];    //DAG, G[i][j]为1表示 盒子i可以嵌套在盒子j中
int vec[35][15];
int dp[35];

//判断x是否小于y
bool is_small(int x, int y){
    for (int i = 1; i <= m; ++i){
        //有一个大于等于则返回0
        if (vec[x][i] >= vec[y][i]){
            return 0;
        }
    }//for(i)
    return 1;
}

void CMAX(int&x, int y){
    if (y > x){
        x = y;
    }
}

int DP(int i){
    int &ans = dp[i];
    if (ans > 0){
        //记忆化搜索,避免重复计算
        return ans;
    }
    ans = 1;
    for (int j = 1; j <= n; ++j){
        if (G[i][j]){
            //递归求解
            CMAX(ans, DP(j) + 1);
        }
    }//for(j)
    return ans;
}

//输出序列
void print_ans(int i){
    if (dp[i] == 1){
        //最后一个节点了
        printf("%d", i);
    }
    else{
        for (int j = 1; j <= n; ++j){
            if (G[i][j] && dp[j] + 1 == dp[i]){
                printf("%d ", i);
                print_ans(j);
                break;
            }    
        }//for(j)    
    }
}

int main()
{
#ifdef _LOCAL
    freopen("D:\input.txt", "r", stdin);
#endif
    while (scanf("%d%d", &n, &m) == 2){
        for (int i = 1; i <= n; ++i){
            for (int j = 1; j <= m; ++j){
                scanf("%d", vec[i] + j);
            }//for(j)
            sort(vec[i] + 1, vec[i] + m + 1);
        }//for(i)
        
        //建DAG
        memset(G, 0, sizeof G);
        for (int i = 1; i <= n; ++i){
            for (int j = 1; j <= n; ++j){
                //G[i][j]为1表示盒子i可以嵌套在盒子j中
                if (is_small(i, j)){
                    G[i][j] = 1;    
                }
            }//for(j)
        }//for(i)

        //求最长路径
        int ans = 0;
        int best;
        memset(dp, 0, sizeof dp);
        for (int i = 1; i <= n; ++i){
            if (DP(i) > ans){
                ans = dp[i];
                best = i;
            }
        }//for(i)
        printf("%d
", ans);
        print_ans(best);
        printf("
");
    }//while(scanf)

    return 0;
}
View Code

       

原文地址:https://www.cnblogs.com/tommychok/p/5361847.html