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