timus_1303_贪心
1303 最小覆盖
题目的大概意思:给一组线段[Li, Ri],Li, Ri都是整数,在这组线段中找出数量最少的线段使这些线段能完全覆盖[0,M]。
输入:
第一行整数M (1 ≤ M ≤ 5000)。
后面是整数对,每对Li, Ri(abs(Li), abs(Ri) ≤ 50000)占一行。最后一行为0 0表示结束。
输出:
第一行打印完全覆盖[0,M]的最小线段数。
后面打印覆盖[0,M]的线段,格式和输入一样。
如果不存在完全覆盖则打印“No solution”
思路:尽量选择覆盖[0,M]长的线段,这也是很明显的,线段覆盖[0,M]越长,完全覆盖[0,M]所需要的线段数必然越少,所以这道题目可以使用贪心尽量选择覆盖[0,M]越长的线段,当然也可以用dp,只是效率差些。dp[k]表示完全覆盖[0,M]的最少线段数,dp[k] = dp[kk] + 1 ,其中kk满足min(0 <= kk < k, [kk, x], x >= k),我的策略是kk在满足(0 <= kk < k, [kk, x], x >= k)的条件下尽量选择最小的kk,这样覆盖[0,M]就会越长。另外一个贪心选择是对于输入,如果线段的左端点相同,只考虑线段长度最长的那个。还有就是对输入的处理,由于线段的两个端点可以是负数和超过5000,所以对于两个端点都是不超过0的数或者都是不小于M的数的线段都直接不予考虑,然后就是线段的左端点为负数的情况,一律将其看做左端点为0.
代码:
#include <stdio.h> typedef struct _pair { int l; int r; int flag; }pair_t; pair_t segment[5001]; int dp[5001]; int path[5001]; int m; void print(int n) { if (n == -1) return; print(path[n]); printf("%d %d\n", segment[n].l, segment[n].r); } int main ( int argc, char *argv[] ) { int l, r; int i, j; int flag; scanf("%d", &m); while (1) { scanf("%d%d", &l, &r); if (l == 0 && r == 0) break; if (l < 0 && r >= 0) { if (segment[0].r < r) //当左端点相同时,选择线段更长的 { segment[0].l = l; segment[0].r = r; segment[0].flag = 1; } } else if (l >= 0 && l <= m) { if (segment[l].r < r) { segment[l].l = l; segment[l].r = r; segment[l].flag = 1; } } } path[0] = -1; flag = 0; for (i = 1; i <= m; i ++) { for (j = 0; j <= i; j ++) if (segment[j].flag && segment[j].r >= i) { if (j == 0 || dp[j]) { dp[i] = dp[j] + 1; path[i] = j; } else flag = 1; break; } if (j > i || flag) break; } if (i <= m) printf("No solution\n"); else { printf("%d\n", dp[m]); print(path[m]); } return 0; } /* ---------- end of function main ---------- */