#10006. 「一本通 1.1 練習 2」數列分段
阿新 • • 發佈:2018-11-21
【題目描述】
對於給定的一個長度為 N 的正整數數列 Ai,現要將其分成連續的若干段,並且每段和不超過 M(可以等於 M),問最少能將其分成多少段使得滿足要求。
【輸入格式】
第一行包含兩個正整數 N,M,表示了數列 Ai 的長度與每段和的最大值;
第二行包含 NNN 個空格隔開的非負整數 Ai。
【輸出格式】
輸出檔案僅包含一個正整數,輸出最少劃分的段數。
【樣例輸入】
5 6
4 2 4 5 1
【樣例輸出】
3
【資料範圍與提示】
對於 20%的資料,有N≤10;
對於 40% 的資料,有N≤1000;
對於 100% 的資料,有 N≤10^5, M≤10^9,MMM 大於所有數的最大值,Ai之和不超過10^9。
思路:啊呀,這絕對是我做loj的貪心以來最簡單的一道題目了,話不多說。說實在的這道題我一看到就想到了dp,(無奈撓額頭的表情),後面想了一下,其實用貪心更簡單,直接模擬判斷就好了。
判斷有兩個:
1.判斷a[i]的值加起來是否比m大
2.判斷如果加起來比m大,ans++
3.判斷最後的單獨一組
是不是簡單的一批,真的很簡單的啦,其實我覺得就是區域性最優解,就是我們要儘可能的使a[i]+起來的值與m最接近, 解釋完畢,就這麼簡單。
【程式碼實現一:詳解版】
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read()//日常快讀 { char c=getchar(); int x=0,f=1; while(c<48 || c>57) { if(c=='-') f=-1; c=getchar(); } while(c>=48 && c<=57) { x=x*10+c-48; c=getchar(); } return x*f; } int a[110000]; int main() { int n,m; n=read(); m=read(); for(int i=1;i<=n;i++) a[i]=read(); int sum=0;//sum是用來記錄當前累積的數的總和 int ans=0;//ans是用來記錄可以成立的組合 for(int i=1;i<=n;i++) { if(sum+a[i]<=m) sum+=a[i]; /* 如果當前sum+a[i]的值小於m,就是他的組合和的限值的話 就把sum更新為當前的a[i] 為什麼要進行這一步呢,因為題目要求的是最少的組合 所以我們要儘量是組合和儘可能大 所以這裡不能直接加,而是要累加,再判斷 */ else//如果sum+a[i]>m的話,說明我們可以把前面的消除,答案+1 { ans++;//答案+1 sum=a[i];//把前面的清零,從當前的這個a[i]繼續往下算 /* 注意很多人容易忘掉這一步,這一步不可以少 因為這一步代表的就是說我們把前面的清掉 是代表前面的成為一組,跟當前我們迴圈到的這個a[i] 沒有半點關係 所以sum一定一定要更新為a[i] 再用當前的a[i]去組合 比如說 4 2 4 m的值為6 那麼我們4+2+4跳到了else這一步 所以我們知道他們的組合不是 4 2 4 而是4 2,所以就要把最後的4留下,其他的換為ans++ */ } } if(sum!=0) ans++; /* 這一步是我重點講解的,前面的都很好理解 這一步是什麼意思呢? 就是說我們一直組合組合,發現組合到最後的那一組的時候 就是剩下的時候,電腦不會給我們自動ans++ 按常理最後剩下沒組合的要自己一個一組 所以這裡我們就要判斷 如果按照了前面的之後,i已經沒有的時候 但是還有數而且比m小的時候 我們就要單獨判斷sum剩下的值,不是0的話說明還要自成一組,ans++ 就拿樣例來說吧 5 6 4 2 4 5 1 前面的4 2先判斷成了一組 然後4 5的時候成了一組 這個時候sum的值為5,到i=5,a[i]=1 但是5+1=6,沒有大於m,所以sum這時變成了6 但實際上這是要成為一組的 所以我們就要在這裡判斷剩下的sum值 剩下了,就ans++,答案加一,組合加一 */ printf("%d\n",ans);//輸出答案 return 0; }
【程式碼實現二:小小的變化】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int a[110000];
int main()
{
int n,m; n=read(); m=read();
for(int i=1;i<=n;i++) a[i]=read();
int sum=0;
int ans=0;
for(int i=1;i<=n;i++)
{
if(sum+a[i]<=m) sum+=a[i];
else
{
ans++;
sum=a[i];
}
}
printf("%d\n",ans+1);//代表最後的組合
return 0;
}
表示蒟蒻並不知道為什麼第二個程式碼會比第一個程式碼多了2ms秒