题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=114&page=show_problem&problem=39
题目大意:给定n个m维箱子,每个箱子有个值,箱子各维数字可以交换。如果某个箱子的每一维都比另外i一个箱子小,那另一个箱子就可以装下这个箱子,问哪哥箱子装的箱子最多,装几个?最后将装在一起的箱子按体积从小到大的顺序输出。
解题思路:状态转移方程很容易想:if (big[j][i] ) dp[j] = max(dp[j],dp[i] + 1) (如果第j个箱子比i大,dp[i]表示装得最多的箱子数)。这个big[j][i]要先算出来,然后直接用就好,就相当于一维数组里的数字大小关系一样。在算big[j][i]之前要先对各个箱子各维的数字排序,然后再对各个箱子按最小一维排序。
测试数据:
5 2
3 7
8 10
5 2
9 11
21 18
8 6
5 2 20 1 30 10
23 15 7 9 11 3
40 50 34 24 14 4
9 10 11 12 13 14
31 4 18 8 27 17
44 32 13 19 41 19
1 2 3 4 5 6
80 37 47 18 21 9
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define MAX 100 struct node { int in,arr[MAX]; }box[MAX]; int cmp(node a,node b) { return a.arr[1] < b.arr[1]; } int main() { int ansi,path[MAX]; int ans,big[MAX][MAX]; int i,j,k,n,m,dp[MAX]; while (scanf("%d%d",&n,&m) != EOF) { for (i = 1; i <= n; ++i) { box[i].in = i; for (j = 1; j <= m; ++j) scanf("%d",&box[i].arr[j]); } for (i = 1; i <= n; ++i) sort(box[i].arr+1,box[i].arr+1+m); sort(box+1,box+1+n,cmp); memset(dp,0,sizeof(dp)); memset(big,0,sizeof(big)); for (i = 2; i <= n; ++i) for (j = 1; j < i; ++j) { for (k = 1; k <= m; ++k) if (box[i].arr[k] <= box[j].arr[k]) break; if (k == m + 1) big[i][j] = 1; } ans = ansi = 1; for (i = 1; i <= n; ++i) dp[i] = 1,path[i] = i; for (i = 2; i <= n; ++i) { for (j = 1; j < i; ++j) if (big[i][j] && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1,path[i] = j; if (dp[i] >= ans) ans = dp[i],ansi = i; } printf("%d\n",ans); k = 1; while (1) { dp[k++] = ansi; if (ansi == path[ansi]) break; ansi = path[ansi]; } for (i = k - 1; i >= 1; --i) printf(i == 1 ? "%d\n" : "%d ",box[dp[i]].in); } }