貪心 -- 局部最優解 -> 全局最優解
Introduction
博才
這邊的教練要求鞏固基礎算法,然而我懷疑我買的一本通是本上的例題的假書
代碼
是假的
,而且例題更是沒有輸入輸出格式
,所以,不管怎樣我是不會按上面來的一定會做題
的
然後我沒有了這個條件,轉而看向競賽寶典,本着鞏固提高的方針看了看貪心
Body
還是一道例題理解一下:
題面
現在有一個數字\(N\),要求去掉\(S\)個數字,使這個數字去掉\(S\)個數字後最小,求去掉後的數字最小是多少?
輸入格式
一行,一個數字\(N\),去掉數字的個數\(S\),中間用空格隔開
輸出格式
一行,一個數字,表示去掉\(S\)個數字後的數字
樣例輸入
314 1
樣例輸出
14
數據範圍
\[0<=S<N<=1e10000\]
首先,因爲我們知道貪心
是一個局部最優解->全局最優解
的算法,所以相當於我們可以把每個步驟求一遍最優解然後繼續求解,所以這個時候我們就可以考慮貪心具體的步驟了
現在請讀者自己思考思考,答案在下方
想出來了嗎?考慮到有一些Markdown編輯器
的不支持的緣故,不採用字體顏色爲白
和註釋
的做法請諒解
答案:
簡單的從高位向低位,然後如果遞減,那麼選擇最前面的一個,也就是該區間最大一個數字,如果遞增,則選擇最後一個,也就是該區間最大的一個數字
Code:
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 10005
char n[maxn];
int len;
inline void Delete_num(int num)
{
for(int i=num;i<len-1;i++) n[i]=n[i+1];
len--;
}
int main()
{
scanf("%s",n);
int s;
scanf("%d",&s);
len=strlen(n);
int now=0;
int st=0;
int ans=s;
bool book=0;
bool flag=0;
while(ans)
{
for(int i=0;i<len;i++)
{
if(i==0)
{
if(n[i]==48) {Delete_num(i);flag=1;break;}
continue;
}
if(n[i]<n[i-1]||(n[i]==n[i-1]&&now==1))
{
if(!now) now=1;
if(now==1) continue;
if(now==2) {Delete_num(i-1);ans--;book=1;now=0;break;}
}
if(n[i]>n[i-1]||(n[i]==n[i-1]&&now==2))
{
if(!now) now=2;
if(now==1){ Delete_num(st);ans--;book=1;now=0;break;}
if(now==2) continue;
}
}
if(flag){flag=0;continue;}
if(book){book=0;continue;}
if(now==1){Delete_num(st);ans--;continue;}
if(now==2){Delete_num(len-1);ans--;}
}
for(int i=0;i<len;i++) printf("%c",n[i]);
return 0;
}
中間的刪除代碼其實就是用時間換空間,如果你想要更少的時間,事實上你可以選擇用空間換時間,空間大小爲10005
即可,所以用空間換時間是一個不錯的選擇,但是由於作者比較懶惰,所以還請讀者自主思考
接下來還是講題:
題面
給定一個由正整數組成的數列,要求你用合併操作合成一個數字,h合併過程如下:
給定兩個數字a
,b
;有合併之後的數字c=a*b+1
;
給定一個數列,求它的極差,也就是最大值和最小值之差
輸入格式
兩行,第一行一個正整數n
第二行n
個正整數表示一個序列
輸出格式
一行,一個數字表示極差
數據範圍和解釋
\(1 \leqslant n \leqslant 100000\)
\(1 \leqslant a_i \leqslant 2147483647(Maxint)\)