UVA - 10599Robots(II)(LIS)

题目: UVA - 10599Robots(II)(LIS)

题目大意:一个N * M 的矩阵,上面有些格子上有垃圾,现在要求一个机器人从1,1的格子出发,往右或是往下走最终到达N * M各格子,沿途要收集最多的垃圾。现在将垃圾编号,要求输出最多能清理的垃圾并且输出这样的清理路线有多少条,输出其中字典序最小的那一条。

解题思路:一开始还以为是简单的dp,结果输出发现路径多了好多条,才发现题意理解的有问题,它只计算捡的垃圾的不同,走哪个格子并不考虑。因为要求要从1,1 到N * M ,并且只能往右或是下,这样的话沿途捡到的垃圾编号一定是递增的,这样问题就转换成在一系列垃圾中找最长的递增序列,但是这里仅仅递增还是不足够的,因为不能往左走,所以还得判断后面的那个垃圾的列是否有大于等于前一个垃圾的列。因为最终都要达到N * M,所以在这个点也手动加上个垃圾,如果这个点没有垃圾的话,就不要加上了。最后记录下选了第i个垃圾前面要选哪一个能够使得LIS最长。
 dp【i】 = dp【k】 + 0  | 1(看这个位置是否有垃圾);

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 105;
const int maxn = 10010;

int rec[N][N];
int f[maxn], num[maxn], s[maxn], y[maxn], d[maxn], p[maxn];
int n, m;

void init (int& cnt) {

	cnt = 0;
	for (int i = 1; i <= n; i++)//将垃圾从小到大的排序
		for (int j = 1; j <= m; j++) {
			if (rec[i][j] || (i == n && j == m)) {

				s[cnt] = (i - 1) * m + j;
				y[cnt] = j;
				d[cnt++] = rec[i][j];
			}
		}
}

void printf_ans (int cnt) {

	if (cnt == -1)
		return;
	printf_ans(p[cnt]);
	if (d[cnt])
		printf (" %d", s[cnt]);
}

int main () {

	int a, b, cnt, cas = 0;
	while (scanf ("%d%d", &n, &m) && n != -1 && m != -1) {

		memset (rec, 0, sizeof (rec));
		while (scanf ("%d%d", &a, &b) , a && b) {

			rec[a][b] = 1;
		}

		init (cnt);

		for (int i = 0; i < cnt; i++) {
			f[i] = 0;//选择第i个垃圾能够捡到的最多的垃圾数目(还没有加上这个点垃圾数目)
			num[i] = 1;//选择第i个垃圾得到最多的垃圾的路线数目
			p[i] = -1;
		}

		for (int i = 0; i < cnt; i++)  {
			for (int j = i - 1; j >= 0; j--) {//为了保证字典序最小

				if (y[j] <= y[i]) {//列坐标

					if (f[j] > f[i]) {
						f[i] = f[j];
						p[i] = j;
						num[i] = num[j];
					} else if (f[j] == f[i]) {

						num[i] += num[j];
						p[i] = j;
					}
				}
			}

			f[i] += d[i];//加上这点的垃圾数目
		}

		printf ("CASE#%d: %d %d", ++cas, f[cnt - 1], num[cnt - 1]);
		printf_ans(cnt - 1);
		printf ("\n");
	}
	return 0;
}
时间: 2024-10-09 12:03:27

UVA - 10599Robots(II)(LIS)的相关文章

UVA - 531Compromise(LIS)

题目:UVA - 531Compromise(LIS) 题目大意:给出两段话,找出里面最长的公共单词的子序列.并且输出任意一个子序列. 解题思路:LIS. 代码: #include <cstdio> #include <cstring> const int N = 105; const int M = 35; char w1[N][M]; char w2[N][M]; int f[N][N]; int p[N][N][2]; int ans[N]; int n1, n2; void

UVa 10599【lis dp,记忆化搜索】

UVa 10599 题意: 给出r*c的网格,其中有些格子里面有垃圾,机器人从左上角移动到右下角,只能向右或向下移动.问机器人能清扫最多多少个含有垃圾的格子,有多少中方案,输出其中一种方案的格子编号.格子编号是从 左上角第一个开始,一行一行的按自然数顺序编.起始行列是第一行第一列.所以例如一个格子的行列号为(ro,co),那么它的编号为bh=(ro-1)*column+co,其中column指这个格子有多少列.(我觉得原题里面有个错误,题目叙述倒数第二行应该是41(6,6)不是41(6,7)).

hdu 5087 Revenge of LIS II(LIS)

题目连接:hdu 5087 Revenge of LIS II 题目大意:给定一个序列,求第2长的LIS长度. 解题思路:用o(n^2)的算法求LIS,每个位置维护两个值,最大和最小即可.注意的是dp[0]中的最大第二大不能都复制成0. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1005; int N, A[maxn],

UVa 10534 DP LIS Wavio Sequence

两边算一下LIS就出来了,因为数据比较大,所以需要二分优化一下. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 10000 + 10; 8 9 int n; 10 11 int a[maxn], l[maxn], r[maxn]; 12 int g

HDU5087 Revenge of LIS II (LIS变形)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5087 题意: 求第二长的最长递增序列的长度 分析: 用step[i]表示以i结尾的最长上升序列的长度,dp[i]表示到i的不同的最长的子序列的个数 然后最后判断最长的子序列的个数是否大于1是的话输出Max,否则输出Max-1 代码如下: #include<cstdio> #include<cstring> #include<algorithm> using namespac

hdu 5087 Revenge of LIS II ( LIS ,第二长子序列)

链接:hdu 5087 题意:求第二大的最长升序子序列 分析:这里的第二大指的是,全部的递增子序列的长度(包含相等的), 从大到小排序后.排在第二的长度 BestCoder Round #16 上的第二题,注意  1 1 2 这组数据,答案应为2 思路1.每次将最长的两个上升子序列长度记录.最后再排序,取第二大的就可以 思路2.假设最长的上升子序列长度(ans)唯一,那第二大应为ans-1 否则,第二大的就为 ans [cpp] view plaincopyprint? #include<std

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

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[0][j] = 0; 伪代码: dp[maxn1][ma

UVA 10869 - Brownie Points II(树状数组)

UVA 10869 - Brownie Points II 题目链接 题意:平面上n个点,两个人,第一个人先选一条经过点的垂直x轴的线,然后另一个人在这条线上穿过的点选一点作垂直该直线的线,然后划分出4个象限,第一个人得到分数为1,3象限,第二个人为二四象限,问第一个个人按最优取法,能得到最小分数的最大值,和这个值下另一个人的得分可能情况 思路:树状数组,可以枚举一点,如果能求出右上和左下点的个数就好办了,其实用一个树状数组,把y坐标离散化掉,然后记录进来,然后把点按x从左往右,每次删掉点后查询