大意:给你一些三维的坐标的箱子,箱子的三维在给定的值内可以任意变换,一个箱子可以无限次使用,求一种方法使得叠箱子的高度最大。
思路:首先看题目的限定条件,即确定长、宽的二维坐标不可能相等,相等则结果是无穷大,这一题的难点主要是在于建图,一开始我是通过排序来建图的,结果算出来了,但感觉比较麻烦,于是去网上看到有一个更加巧妙的方法,他是没有排序而直接建图的。
建好图后,就是简单DAG上的最长路径了,记忆化搜索解之,d[i]表示以i为起点的最长路径的长度。
如果这题推广到多维的话,那么无论是排序还是其他的方法似乎都不太好建图,那样的话,只有加上每个箱子只能使用一次这个限制条件似乎才方便建图。
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <map> #include <queue> using namespace std; const int MAXN = 1010; struct Edge { int x, y, z; }A[MAXN]; int d[MAXN]; int G[MAXN][MAXN]; bool vis[MAXN]; int n; int times; void init() { memset(G, 0, sizeof(G)); memset(vis, 0, sizeof(vis)); } int check(int i, int j) { if((A[i].x > A[j].x && A[i].y > A[j].y) || (A[i].x > A[j].y && A[i].y > A[j].x)) return 1; return 0; } void build() { for(int i = 0; i < 3*n; i++) { for(int j = 0; j < 3*n; j++) { if(check(i, j)) { G[i][j] = 1; } } } } int dp(int i) { int& ans = d[i]; if(vis[i]) return ans; vis[i] = 1; ans = A[i].z; for(int j = 0; j < 3*n; j++) if(G[i][j]) ans = max(ans, dp(j)+A[i].z); return ans; } int read_case() { init(); scanf("%d", &n); if(!n) return 0; for(int i = 0; i < n; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); A[3*i].x = x, A[3*i].y = y, A[3*i].z = z; A[3*i+1].x = x, A[3*i+1].y = z, A[3*i+1].z = y; A[3*i+2].x = y, A[3*i+2].y = z, A[3*i+2].z = x; } return 1; } void solve() { build(); int ans = 0; for(int i = 0; i < 3*n; i++) ans = max(ans, dp(i)); printf("Case %d: ", ++times); printf("maximum height = %d\n", ans); } int main() { times = 0; while(read_case()) { solve(); } return 0; }
列出全排列:
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <map> #include <queue> using namespace std; const int MAXN = 1010; struct Edge { int x, y, z; }A[MAXN]; int d[MAXN]; int G[MAXN][MAXN]; bool vis[MAXN]; int n; int times; int tot; void init() { tot = 0; memset(G, 0, sizeof(G)); memset(vis, 0, sizeof(vis)); } int check(int i, int j) { if((A[i].x > A[j].x && A[i].y > A[j].y) || (A[i].x > A[j].y && A[i].y > A[j].x)) return 1; return 0; } void build() { for(int i = 0; i < tot; i++) { for(int j = 0; j < tot; j++) { if(check(i, j)) { G[i][j] = 1; } } } } int dp(int i) { int& ans = d[i]; if(vis[i]) return ans; vis[i] = 1; ans = A[i].z; for(int j = 0; j < tot; j++) if(G[i][j]) ans = max(ans, dp(j)+A[i].z); return ans; } int read_case() { init(); scanf("%d", &n); if(!n) return 0; for(int i = 0; i < n; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); A[tot].x = x, A[tot].y = y, A[tot++].z = z; //1 A[tot].x = x, A[tot].y = z, A[tot++].z = y; A[tot].x = y, A[tot].y = x, A[tot++].z = z; //2 A[tot].x = y, A[tot].y = z, A[tot++].z = x; //3 A[tot].x = z, A[tot].y = x, A[tot++].z = y; A[tot].x = z, A[tot].y = y, A[tot++].z = x; } return 1; } void solve() { build(); int ans = 0; for(int i = 0; i < tot; i++) ans = max(ans, dp(i)); printf("Case %d: ", ++times); printf("maximum height = %d\n", ans); } int main() { times = 0; while(read_case()) { solve(); } return 0; }