uva103(最长递增序列,dag上的最长路)

题目的意思是给定k个盒子,每个盒子的维度有n dimension

问最多有多少个盒子能够依次嵌套

但是这个嵌套的规则有点特殊,两个盒子,D = (d1,d2,...dn) ,E = (e1,e2...en) 只要盒子D的任意全排列,小于盒子E,那么就说明

盒子D能放入盒子E中,其实就是将两个盒子的维度排序,如果前一个盒子的维度依次小于后一个盒子,那么就说明前一个盒子能放入后一个盒子中

这个题目能够转化为最长递增子序列。

首先将盒子的维度从小到大排序,然后将k个盒子,按照排序后的第一维度从小到大排序

这样中的目的是,后面的盒子一定放不到前面的盒子里面,这样是为了消除无后效性。

如果不排序,那么将有后效性,比如第一个盒子不选,但是第二个盒子可以放到第一个盒子里面。

然后就转化为最长递增序列的问题了。

 1 /*
 2 感觉像是变形的最长递增子序列
 3 如何快捷的判断一个盒子进过变换能放到另一个盒子里面呢?
 4 */
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <algorithm>
 8 using namespace std;
 9 const int INF = 1<<30;
10 struct node
11 {
12     int minNum;
13     int id;
14     int dimension[10];
15     bool operator<(const node&rhs)const
16     {
17         return minNum < rhs.minNum;
18     }
19 }a[33];
20 bool canInput[33][33];//canInput[i][j]判断j能不能放到i里面去
21 int dp[100];
22 int path[33];
23 int ans[100];
24 int main()
25 {
26
27     int n,k,i,j,z;
28     while(scanf("%d%d",&k,&n)!=EOF)
29     {
30         memset(ans,0,sizeof(ans));
31         memset(canInput,false,sizeof(canInput));
32         memset(dp,0,sizeof(dp));
33         for(i=0; i<k; ++i)
34         {
35             dp[i] = 1;
36             path[i] = i;
37             a[i].minNum = INF;
38             a[i].id = i+1;
39             for(j=0; j<n; ++j)
40             {
41                 scanf("%d",&a[i].dimension[j]);
42                 a[i].minNum = min(a[i].minNum,a[i].dimension[j]);
43             }
44             sort(a[i].dimension,a[i].dimension+n);
45         }
46
47         sort(a,a+k);
48         for(i=0; i<k; ++i)//预处理,判断i能不能放到j里面去
49             for(j=i+1; j<k; ++j)
50             {
51                 bool can = true;
52                 for(z=0; z<n; ++z)
53                 {
54                     if(a[i].dimension[z] >= a[j].dimension[z])
55                         can = false;
56                 }
57                 if(can)
58                     canInput[j][i] = true;
59             }
60         //这里就是求最长递增子序列,时间复杂度是O(k*k)
61         for(i=0; i<k; ++i)
62             for(j=0; j<i; ++j)
63             {
64                 if(canInput[i][j])//预处理之后,就变成了一维的最长递增子序列的求解了
65                 {
66                     if(dp[j]+1 >dp[i])
67                     {
68                         dp[i] = dp[j]+1;
69                         path[i] = j;
70                         //break; 这里可不能break, 比如例子:1 2 3 4 5 11 12 13 10 14
71                     }
72                 }
73             }
74         int cnt = 0,index;
75         for(i=0; i<k; ++i)
76             if(cnt < dp[i])
77             {
78                 cnt = dp[i];
79                 index = i;
80             }
81
82         printf("%d\n",cnt);
83         ans[--cnt] = a[index].id;
84
85         while(path[index]!=index)
86         {
87             ans[--cnt] = a[path[index]].id;
88             index = path[index];
89         }
90         printf("%d",ans[cnt++]);
91         while(ans[cnt]!=0)
92         {
93             printf(" %d",ans[cnt++]);
94         }
95         puts("");
96     }
97     return 0;
98 }

当然也可以建图(dag图),然后求最长路, 最长路的一种求法就是进行拓扑排序,然后进行最长递增子序列dp,  拓扑排序同上面的排序一样,也是为了消除后效性

然后这种做法,相当于上面,太复杂了。 但是是为了天马行空的想法而A题,而不是为了A题而A题。

  1 /*
  2 建图(dag图),
  3 拓扑排序
  4 dp
  5 */
  6
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <algorithm>
 10 #include <stack>
 11 using namespace std;
 12 const int INF = 1<<30;
 13 struct node
 14 {
 15     int dimension[10];
 16
 17 }a[33];
 18 bool canInput[33][33];//canInput[i][j]判断i能不能放到j里面去
 19 int dp[100];
 20 int path[33];
 21 int ans[100];
 22 int in[30];
 23 int sequeue[30];
 24 int main()
 25 {
 26     int n,k,i,j,z;
 27     while(scanf("%d%d",&k,&n)!=EOF)
 28     {
 29         memset(ans,0,sizeof(ans));
 30         memset(canInput,false,sizeof(canInput));
 31         memset(dp,0,sizeof(dp));
 32         memset(in,0,sizeof(in));
 33         for(i=0; i<k; ++i)
 34         {
 35             dp[i] = 1;
 36             path[i] = i;
 37             for(j=0; j<n; ++j)
 38             {
 39                 scanf("%d",&a[i].dimension[j]);
 40             }
 41             sort(a[i].dimension,a[i].dimension+n);
 42         }
 43
 44         for(i=0; i<k; ++i)//预处理,建图
 45             for(j=i+1; j<k; ++j)
 46             {
 47                 bool can = true;
 48                 for(z=0; z<n; ++z)
 49                 {
 50                     if(a[i].dimension[z] >= a[j].dimension[z])
 51                         can = false;
 52                 }
 53                 if(can)
 54                     canInput[i][j] = true;
 55                 can = true;
 56                 for(z=0; z<n; ++z)
 57                 {
 58                     if(a[i].dimension[z] <= a[j].dimension[z])
 59                         can = false;
 60                 }
 61                 if(can)
 62                     canInput[j][i] = true;
 63
 64             }
 65         //每个结点的入度
 66         for(i=0; i<k; ++i)
 67         {
 68             for(j=0; j<k; ++j)
 69                 if(canInput[i][j])
 70                     in[j]++;
 71         }
 72         //拓扑排序,sequeue数组存在排序之后的序列
 73         for(i=0; i<k; ++i)
 74         {
 75             for(j=0; in[j]&&j<k; ++j)
 76                 NULL;
 77             in[j] = -1;
 78             sequeue[i] = j;
 79             for(z=0; z<k; ++z)
 80                 if(canInput[j][z])
 81                     in[z]--;
 82         }
 83
 84         //对拓扑排序之后的序列进行最长递增子序列的dp
 85         for(i=0; i<k; ++i)
 86             for(j=0; j<i; ++j)
 87             {
 88                 if(canInput[sequeue[j]][sequeue[i]] && dp[j]+1>dp[i])//sequeue[i]
 89                 {
 90                     dp[i] = dp[j]+1;
 91                     path[i] = j;
 92                 }
 93             }
 94         int cnt = 0,index;
 95         for(i=0; i<k; ++i)
 96             if(cnt < dp[i])
 97             {
 98                 cnt = dp[i];
 99                 index = i;
100             }
101         printf("%d\n",cnt);
102
103         ans[--cnt] = index;
104         while(path[index] != index)
105         {
106             ans[--cnt] = path[index];
107             index = path[index];
108         }
109         //sequeue[i]
110         printf("%d",sequeue[ans[cnt++]]+1);
111         while(ans[cnt]!=0)
112         {
113             printf(" %d",sequeue[ans[cnt++]]+1);
114         }
115         puts("");
116     }
117     return 0;
118 }

时间: 2024-08-04 14:15:09

uva103(最长递增序列,dag上的最长路)的相关文章

zoj1986 Bridging Signals (dp,最长递增序列,LIS)

A - Bridging Signals Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Submit Status Practice ZOJ 1986 Description 'Oh no, they've done it again', cries the chief designer at the Waferland chip factory. Once more the routing designer

矩形网格中寻找最长递增序列

在矩形网格中寻找最长的递增序列 比如如下网格 97,47,56,36 35,57,41,13 89,36,98,75 25,45,26,17 结果要求输出 17, 26, 36, 41, 47, 56, 57, 97 基本想法就是对图中的每一个点都当作起始点试一编 将序列最长的保存起来 最后输出 代码如下 使用java编写 import java.util.ArrayList; public class 最长递增序列 { static int[][] rect={ {97,47,56,36},

POJ 2533 Longest Ordered Subsequence 最长递增序列

Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, seque

数据结构与算法学习之路:LIS——最长递增序列的动态规划算法和二分思想算法

一.最长递增序列的问题描述: 求一个整数序列的最长递增子序列,子序列不要求是连续的.例如: Input:4,6,9,6,7,6,3,8,10:Output:5 二.解决方法: 1.用动态规划的方法解决.从问题我们可以知道,我们最终得到的最长递增子序列,其任意一段子序列也是对应序列中的最长子序列.这样说可能不好理解,就以上面的例子来说: 最长子序列为:4,6, 7, 8, 10.在这段子序列的子序列里选一个,例如:4,6,7.则4,6,7也是4,6,9,6,7,6,3这段序列的最长子序列. 对于动

Leetcode 674.最长递增序列

最长递增序列 给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1,3,5], 长度为3. 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开. 示例 2: 输入: [2,2,2,2,2] 输出: 1 解释: 最长连续递增序列是 [2], 长度为1. 注意:数组长度不会超过10000. 思路 1 class Solution { 2 public int find

NYOJ_矩形嵌套(DAG上的最长路 + 经典dp)

本题大意:给定多个矩形的长和宽,让你判断最多能有几个矩形可以嵌套在一起,嵌套的条件为长和宽分别都小于另一个矩形的长和宽. 本题思路:其实这道题和之前做过的一道模版题数字三角形很相似,大体思路都一致,这道题是很经典的DAG上的最长路问题,用dp[ i ]表示以i为出发点的最长路的长度,因为每一步都只能走向他的相邻点,则 d[ i ]  = max(d[ j ] + 1)这里 j 是任意一个面积比 i 小的举行的编号. 下面的代码中附带了最小字典序最长路打印的问题,我们找到第一个路径最长的 i,往后

LIS(最长的序列)和LCS(最长公共子)总结

LIS(最长递增子序列)和LCS(最长公共子序列)的总结 最长公共子序列(LCS):O(n^2) 两个for循环让两个字符串按位的匹配:i in range(1, len1) j in range(1, len2) s1[i - 1] == s2[j - 1], dp[i][j] = dp[i - 1][j -1] + 1; s1[i - 1] != s2[j - 1], dp[i][j] = max (dp[i - 1][j], dp[i][j - 1]); 初始化:dp[i][0] = dp

ACM: Racing Gems - 最长递增序列

Racing Gems   You are playing a racing game.  Your character starts at the x axis (y = 0) and proceeds up the      race track, which has a boundary at the line x = 0 and another at x = w.  You  may start the race       at any horizontal position you

最长递增子序列(输出最长递增序列 及其长度)

最长递增子序列的解法有很多种,常用的有最长公共子序列法.动态规划.记录所有递增序列长度最大值的方法. 最长公共子序列法:如例子中的数组A{5,6, 7, 1, 2, 8},则我们排序该数组得到数组A‘{1, 2, 5, 6, 7, 8},然后找出数组A和A’的最长公共子序列即可.显然这里最长公共子序列为{5, 6, 7, 8},也就是原数组A最长递增子序列. 在http://blog.csdn.net/yysdsyl/article/details/4226630中有详细解释. 动态规划:参见h