標籤:http io for 問題 cti 代碼 ar c++
題目:uva10148Advertisement(區間選點)
題目大意:給出n個慢跑選手的慢跑區間,要求每個選手的區間至少要由k個廣告,但是如果這個選手的慢跑區間長度放不下K個廣告的話(特殊區間),那麼就將這個選手的區間內都放滿廣告就可以了。問要滿足上訴的要求,最少需要多少數量的廣告,並且要找廣告編號從小到大輸出。
解題思路:區間選點問題。先將這些區間【a,b】按照b從小到大排序。如果b相同的話就按照a從大到小排序,這樣保證前面的區間比後面的區間要小。每次選點的後都選靠近邊界的點。這裡要注意的是這裡是要選K個點。但是這個區間內的可能會已經被前面的區間選了。所以這裡要判斷一下,這些點有沒有被選。還需要判斷這個區間是否是特殊的區間。
代碼:
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int N = 1005;const int M = 20005;int k, n;int visit[M]; //標記點選擇狀態struct jogger {int a, b;}jo[N];int cmp (const jogger &a, const jogger &b) {if (a.b == b.b)return a.a > b.a;return a.b < b.b;}int solve () {int count = 0;int s = -M;int c;memset (visit, 0, sizeof (visit));for (int i = 0; i < n; i++) {if (jo[i].a > s) { //後一個區間和前一個區間沒有重合//printf ("%d\n", jo[i].b - jo[i].a + 1);if (jo[i].b - jo[i].a + 1 <= k) { //特殊的區間for (int j = jo[i].a; j <= jo[i].b; j++) visit[j + 10000] = 1;count += jo[i].b - jo[i].a + 1;} else {//printf ("----\n");for (int j = jo[i].b; j > jo[i].b - k; j--)visit[j + 10000] = 1;count += k;}s = jo[i].b;} else {c = 0; //由重合的話,需要統計一下這個區間已將選擇的點的個數。for (int j = jo[i].a; j <= s; j++)if (visit[j + 10000])c++;if (jo[i].b - jo[i].a + 1 <= k) { //特殊的區間if (c >= jo[i].b - jo[i].a + 1)continue;for (int j = jo[i].b; j >= jo[i].a; j--) {if (visit[j + 10000])continue;visit[j + 10000] = 1;count++;}s = jo[i].b;} else {if (c >= k)continue;int m = 0;for (int j = jo[i].b; j >= jo[i].a; j--) {if (m + c == k)break;if (visit[j + 10000])continue;visit[j + 10000] = 1;count++;m++;}s = jo[i].b;}}}return count;}int main () {int t;int a, b;scanf ("%d", &t);while (t--) {scanf ("%d%d", &k, &n);for (int i = 0; i < n; i++) {scanf ("%d%d", &a, &b);if (a < b) {jo[i].a = a;jo[i].b = b;} else {jo[i].a = b;jo[i].b = a;}}sort (jo, jo + n, cmp);int count = solve();printf ("%d\n", count);for (int i = 0; i < M; i++) if (visit[i])printf ("%d\n", i - 10000);if (t)printf ("\n");}return 0;}