POJ-1505&&UVA-714 抄書(貪心+二分)
阿新 • • 發佈:2019-01-26
題目傳送門:http://poj.org/problem?id=1505
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=655
題目大意:
有k個本書,m個人,第i本書有ai頁,m個人想把書抄完,但是誰都不想讓其中一個人偷懶,讓你在不改變書的順序的情況下把書分成m份,使得所有人中分到的書的頁數的最小值儘量的大,測試資料有多組。
輸入
第一行輸入一個整數n,表示有n組測試資料;每組測試資料包含行,第一行有兩個整數k,m(1 <= k <= m <= 500).第二行有k個整數,第i個表是第i本書的頁數。
輸出
輸出k個整數,並用 ‘/’ 把分書的方式表示出來,如果有多組,則讓第一人的書儘量少,如果還有多組,讓第二人的書儘量少,以此類推
Sample Input
2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
Sample Output
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100
困擾我6個小時的小bug,第一次發,紀念一下。
解題思路: 套路1:求解最小值的最大值,一般二分答案來進行。
二分模板
int check(int mid)
{
if(***) return 1;
return 0;
}
int solve(int l,int r)
{
while(l<=r)
{
int mid=l+(r-l)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
return l-1;
}
貪心原則:儘量滿組最右邊的人,讓他拿到的頁數儘量的多。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int a[550];
int vis[550];
int k,m;
int check(int x)
{
int sum=0;
int c=1;
for(int i=k-1;i>=0;i--)
{
if(a[i]+sum > x)
{
c++;
sum=a[i];
if(c > m) return 0;
}
else sum += a[i];
}
return 1;
}
void print(int x)
{
int sum=0;
int co=1;
for(int i=k-1;i>=0;i--)
{
if(sum+a[i] > x)
{
sum=a[i];
co++;
vis[i]=1;
}
else sum += a[i];
if(m-co == i+1)
{
for(int j=0 ; j <= i ;j++)
vis[j] = 1;
break;
}
}
for(int i=0;i<k-1;i++)
{
printf("%d ",a[i]);
if(vis[i]) printf("/ ");
}
printf("%d\n",a[k-1]);
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
memset(vis,0,sizeof(vis));
scanf("%d%d",&k,&m);
long long sum=0;
long long l=-1,r=0;
for(int i=0;i<k;i++)
{
scanf("%d",&a[i]);
if(l < a[i]) l = a[i];
r += a[i];
}
while(l<=r)
{
long long mid=(l+r)/2;
if(check(mid)) r=mid-1;
else l=mid+1;
}
print(l);
}
return 0;
}
題目不是很複雜,但是我提交了自我以為正確了,提交了20+次,全部WA。最後看了一整個下午才看出來。這裡是貪心法的判斷與二分之間的一個小小的衝突,就是對於二分的下界要求一定要是所有資料中的最大值,因為如果比其小的話,有可能在某個二分值判斷的時候剛剛好加上某個本身就大於mid的值,這樣在劃分的時候就會有這個大比mid大的值獨自分在一組,但事實上這種情況是不合法的,當有這樣的數出現時,就行該判斷出而分出的答案小了。