1. 程式人生 > 其它 >UVa1442 洞穴(掃描法)紫書訓練

UVa1442 洞穴(掃描法)紫書訓練

技術標籤:紫書第8章c++

題目大意:有一個山洞用於存放石油,給出山洞的長度n,以及每個位置的底高度以及頂高度,要求存放石油不能沒過頂,求最大的放油量。

做題感受:挺離譜的,我自己莫名其妙想的用滑動視窗做,反正做了好幾個小時沒做出來,最後還是去看了lrj的分析,看到他的程式碼是真的短,我自己寫了半天還寫的賊長,反正真的是佩服。

分析:設level=s[0],判斷[i,i+1]處的高度(其實level也就是i的高度,i則是i+1的高度,i和i+1進行比較)從左至右掃描,如果p[i]>level,說明水被阻隔了,需要把level提升至p[i].如果s[i]<level,說明水位太高,需要把level降低至s[i].從右向左掃描同理,反正這麼說估計也不一定能聽懂(說實話我還沒完全搞懂,不過舉個例子看是真的很清楚,就是還是不知道為什麼會這樣)還是舉個例子吧.

例子:
在這裡插入圖片描述
紅線是從左到右掃描的結果,藍線試從右到左掃描的結果。
兩次掃描完以後,藍色的線和紅色的線誰低誰就減去p[i],也就是黑色覆蓋的範圍,就是最終答案.
在這裡插入圖片描述
這樣應該有大致的感覺能明白一點這裡面的道理了。

下面是程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 5;
int p[maxn],s[maxn],h[maxn];
int main()
{
	int i, n, j, t, sum,l, r;
	cin >> t;
	while (t--)
	{
		sum = 0;
		cin >>
n; for (i = 0; i < n; i++) cin >> p[i]; for (i = 0; i < n; i++) cin >> s[i]; l = s[0]; for (i = 0; i < n ; i++)//從左到右掃描 { if (p[i] > l)l = p[i]; if (s[i] < l)l = s[i]; h[i] = l;//將level的值儲存進h[i],也就是例子中的紅線部分 } l = s[n - 1]; for (i = n - 1; i >= 0; i--
)//從右到左掃描 { if (p[i] > l)l = p[i]; if (s[i] < l)l = s[i]; sum += min(h[i], l) - p[i];//掃描的同時可以直接求出答案.min(h[i],l)也就是紅線和藍線比較後最低的位置 } cout << sum << endl; } return 0; }