洛谷 P2101 命運石之門的選擇 (分治)
阿新 • • 發佈:2020-11-21
P2101 命運石之門的選擇 (分治)
介紹
El Psy Congroo
題目連結
沒錯,作為石頭門廚,怎麼能不做石頭門的題呢?(在搜石頭門的時
候搜到了本題)
本題作為一道分治基礎練習題還是不錯的,雖然看起來挺簡單,但還
是有不少需要思考的地方的。(可能是我太菜了)
分析
我們對本題進行分析,
就拿下面這個圖舉例
我們首先觀察到了紅色部分,紅色部分是當前所能構成的最大矩形
我們擁有兩種塗色方法,橫著塗和豎著圖,因為塗一次色的代價與塗
色面積無關,所以我們每一次塗色需要儘可能的多塗。
對於紅色部分,顯然,全部採用同一種塗色方法是要比兩
種方法同時採取更優的,因為當我們混用塗色方法時,一定是可以
通過去掉某一次塗色來降低所需代價的。
針對紅色部分,如果我們全部採用豎著塗,因為我們要儘可能的多
塗,所以我們既然可以豎著塗完紅色部分,也可以在同代價下塗完
整個圖,所以我們目前塗完整個圖的代價就是當前圖形的寬度,如
果我們採用橫著圖,塗完整張的總代價就是(該圖形中最低的小矩
形的高度)+(塗完紅色部分以外部分的最小代價)
我們所要求的答案就是這兩種方法的代價最小值
那如何求出塗完紅色部分以外部分的最小代價呢?
這時候就要採用分治思想了,
我們用原圖形減去紅色部分,得到了一個或幾個圖形,我們目前要
求的就是塗完所有新圖形的最小代價,我們針對每一個新圖形都按
先前求原圖形的最小代價的方法處理,最後將其合併即可。
放一下程式碼
#include<cstdio> #include<cstring> #include<string> #include<iostream> #define int long long using namespace std; const int maxn=1e4; inline int read(){ int ret=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-f; ch=getchar(); } while(ch<='9'&&ch>='0'){ ret=ret*10+(ch^'0'); ch=getchar(); } return ret*f; } int n; int m; int a[maxn]; int slove(int l,int r){ if(l==r){ return 1;//邊界 } int t=r-l+1;//目前圖形的寬度 int minn=0x3f3f3f3f; for(int i=l;i<=r;i++){ if(a[i]<minn){ minn=a[i];//找到最低矩形的高度 } } int ans=minn; for(int i=l;i<=r;i++){ a[i]-=minn;//減掉紅色部分 } int ll=l; for(int i=l;i<=r;i++){ if(a[i]&&!a[i-1]) ll=i; if(a[i]&&(!a[i+1]||i==r)){ ans+=slove(ll,i);//分治處理 } } return min(ans,t); } signed main(){ // freopen("a.txt","r",stdin); n=read(); for(int i=1;i<=n;i++){ a[i]=read(); } cout<<slove(1,n); return 0; }
這一切都是命運石之門的選擇