題意:
給你n個任務區間,
你可以選擇起點,每次你可以 向左 走一步或者兩步,或者向右走兩步或一步
請你依次到達所有的區間,最少需要多少次
思路:
比賽的時候看錯兩次題,第一次沒有看到依次,比賽過程中看到了,把排序貪心改掉了,但是還是看錯了題,我一直以爲是隻能向左一步和向右兩步…
參考博客
我看到好多博客都是直接先合併所有重合的區間,然後再進行移動算次數,這種寫法明顯不對,但是數據太水,居然給過了
hack數據如下
4
1 2
4 5
5 6
10 10
答案應該爲4,但是如果提前合併了區間,答案就爲5
我的思路爲:
用兩個數字l, r,代表每一次執行任務前我的點在區間之間,由於起點可以隨意起,於是我初始化爲l = 1, r = 1000000,每次加入新的任務區間,更新當前點所在的區間,已經加入到這個區間的最短距離
1.如果有重合的部分就直接取重合的部分,不用移動
2.如果不重合,判斷該區間與任務區間的距離爲偶數則直接到達任務區間的端點最優,如果爲奇數,那我們走一樣的步數可以到達任務區間的的端點和相鄰的點,則將區間更新爲任務區間的端點和其相鄰的點(建立在下一個任務區間長度大於1的前提下)
爲什麼我們要直接記錄點的區間到不能直接取任務區間的端點作爲到達的終點,因爲如果存在當前區間與下一個任務區間長度爲奇數,而我們用同樣的步數可以到達兩個終點,但是我們如果選擇任務區間的端點來作爲終點,如果下下任務區間與該端點的距離爲奇數且比下下任務區間與該端點的相鄰點的距離的大的話就不是最優的
#include<bits/stdc++.h>
using namespace std;
int l, r;
int solve(int x, int y) {
int ll = max(x, l);
int rr = min(y, r);
if(ll <= rr) {
l = ll;
r = rr;
return 0;
}
int res;
if(y < l) { //新的任務區間在左邊
res = (l - y + 1) / 2;
r = y;
if((l - y) % 2 == 1 && x != y) {
l = y - 1;
} else {
l = y;
}
} else {//新的任務區間在右邊
res = (x - r + 1) / 2;
l = x;
if((x - r) % 2 == 1 && x != y) {
r = x + 1;
} else {
r = x;
}
}
return res;
}
int main() {
int t, n, x, y;
cin>>t;
while(t--) {
cin>>n;
int ans = 0;
l = 1, r = 1000000;
while(n--) {
cin>>x>>y;
ans += solve(x, y);
}
cout<<ans<<endl;
}
return 0;
}