Yêu cầu: Cho a, b và vị trí của n cây. Hãy tìm đoạn đường có độ dài ngắn nhất mà dọc theo đó có ít nhất a cây tùng và có ít nhất b cây trúc.
Dữ liệu: Vào từ file văn bản MINROAD.INP:
* Dòng đầu chứa 3 số nguyên dương n, a, b (a + b ≤ n);
* Dòng thứ i trong n dòng tiếp theo, mỗi dòng chứa hai số nguyên dương di (di ≤ 109) và ki, trong đó di là khoảng cách của cây tính từ vị trí bắt đầu của con đường, ki = 1 nếu là cây tùng, ki = 2 nếu là cây trúc.
Các số trên cùng một dòng được ghi cách nhau ít nhất một dấu cách.
Kết quả: Ghi ra file văn bản MINROAD.OUT một số nguyên là độ dài đoạn đường ngắn nhất tìm
được, quy ước ghi số -1 nếu không tồn tại đoạn đường nào thỏa mãn điều kiện đặt ra.
[Input example]
7 2 2
20 2
30 1
25 1
35 1
60 2
65 2
10 1
[Output example]
35
[Giải thuật]
* Sắp xếp dãy vị trí của các cây theo thứ tự tăng dần: d[1] < d[2] <...
* Bắt đầu từ đầu dãy, duyệt từ trái qua phải để tìm các đoạn gồm dãy các phần tử liên tiếp chứa ít nhất a cây tùng và ít nhất b cây trúc. Mỗi lần tìm được đoạn như vậy ghi nhận độ dài để tìm ra đoạn ngắn nhất.
#include <cstdio>
#include <iostream>
#include<stdlib.h>
using namespace std;
#define nmax 300000
long data[nmax][2];
int compare(const void *arg1, const void *arg2)
{
int const *lhs = static_cast<int const*>(arg1);
int const *rhs = static_cast<int const*>(arg2);
return (lhs[0] < rhs[0]) ? -1
: ((rhs[0] < lhs[0]) ? 1
: (lhs[1] < rhs[1] ? -1
: ((rhs[1] < lhs[1] ? 1 : 0))));
};
int main(int argc, char** argv)
{
freopen("MINROAD.INP", "r", stdin);
freopen("MINROAD.OUT", "w", stdout);
int n, a, b;
scanf("%d %d %d", &n, &a, &b);
if (a == 0 && b == 0){
printf("%d", -1);
return 0;
}
for (int i = 0; i < n; i++)
scanf("%d %d", &data[i][0], &data[i][1]);
qsort(data, n, 2 * sizeof(int), compare);
long min = 1000000000;
int head, tail = 0;
int countTung = 0;
int countTruc = 0;
for (int i = 0; i < n; i++){
if (data[i][1] == 1){
countTung++;
}
else{
countTruc++;
}
if (countTung >= a && countTruc >= b){
head = i;
min = data[head][0] - data[tail][0];
break;
}
}
bool isSub = false;
while (head < n){
for (int j = tail; j < head; j++){
isSub = false;
if (data[j][1] == 1 && countTung >a){
countTung --;
tail += 1;
isSub = true;
}
if (data[j][1] !=1 && countTruc >b){
countTruc--;
tail += 1;
isSub = true;
}
if(!isSub) break;
if (data[head][0] - data[tail][0] < min){
min = data[head][0] - data[tail][0];
}
}
head++;
if (head < n){
if (data[head][1] == 1){
countTung++;
}
else{
countTruc++;
}
}
}
if (min == 1000000000){ min = -1; }
printf("%d", min);
return 0;
}

0 Comment to "[Bài tập mẫu] Con đường Tùng - Trúc."
Post a Comment