56 条题解
-
11PowderHan LV 10 @ 2017-05-07 12:51:58
/* 好题~ 学习了~ 一开始看到这题很容易想到那道经典的派(openjudge上有) 那是一道典型的二分啊~ 这里也可以用到二分但是并不一样 这里我们可以二分可以满足的人的数量 首先我们要弄清这么一个事实 如果是为了满足尽可能多的人 我们满足嘴巴小的必然要比满足嘴巴大的好 这个贪心决策很容易证明的 如果同一块蛋糕一个嘴巴大的人能正好分到那一部分 那么换一个嘴巴小的必然也能分到 还有可能因此多分到几个人 所以我们可以发现先分嘴巴小的不会丢失最优解 那么我们很容易就想到先按照嘴巴大小排个序 那么我们二分这个满足人数mid后 就要考虑是否能使mouth[1]~mouth[mid]都满足 因为蛋糕的大小是不定的 所以我们可以用dfs来完成 即枚举每一个嘴巴是用哪一块来填饱 首先我们记录下蛋糕总数sum 然后维护嘴巴大小的前序和数组s[] 那么首先我们很容易想到 对于排序后的mouth数组的前序和递增数组s[] 如果总的sum比某个s[i]还要小 那么根本没必要以i为二分右界 因为不管怎么样是不可能满足的 所以我们可以先缩小二分区域 在搜索这里需要加上剪枝 我们用waste来记录当前浪费的蛋糕数量 怎么叫浪费呢 就是某一块切去这个人吃的之后连mouth[1]都满足不了了 那么剩下的这些必然是浪费了 这个只要在dfs时维护一个全局变量waste就可以了 第二个剪枝 如果对于排序后的mouth数组 dfs过程有mouth[k]==mouth[k-1] 那么我们可以直接dfs(k-1,i) 因为如果某个i不可以填满mouth[k]的话 那么mouth[k-1]必然也填不满 所以没有必要重新判断一次 这样的话可以在12个点20ms的时间内出解 还是挺快的 关键是要学会一些常用的剪枝手段~ 涨姿势~! 关于二分之后答案的输出 窝太弱啦一向迷糊 干脆直接加上一个ans来记录 就万无一失啦~ */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN=55; const int MAXM=1030; int s[MAXM]; int cake[MAXN],fcake[MAXN]; int mouth[MAXM]; int n,m,sum; int waste,mid; int ans; void init() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&cake[i]); sum+=cake[i]; } scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&mouth[i]); sort(mouth+1,mouth+m+1); for(int i=1;i<=m;i++) s[i]=s[i-1]+mouth[i]; } bool dfs(int k,int cur)//要满足k个人,当前到了cur { if(k<=0) return 1; if(sum-waste<s[mid]) return 0; for(int i=cur;i<=n;i++) if(fcake[i]>=mouth[k]) { fcake[i]-=mouth[k]; if(fcake[i]<mouth[1]) waste+=fcake[i]; if(mouth[k]==mouth[k-1]) { if(dfs(k-1,i)) return 1; } else if(dfs(k-1,1)) return 1; if(fcake[i]<mouth[1]) waste-=fcake[i]; fcake[i]+=mouth[k]; } return 0; } int main() { init(); while(sum<s[m]) m--; int l=0,r=m; while(l<=r) { waste=0; for(int i=1;i<=n;i++) fcake[i]=cake[i]; mid=(l+r)>>1; if(dfs(mid,1)) l=mid+1,ans=max(ans,mid); else r=mid-1; } cout<<ans<<endl; return 0; }
-
12018-11-25 16:58:50@
/*把人按口的大小排序,并记录前缀和与蛋糕总数,显然,前缀和是递增的,那么这样,我们可以通过缩小二分范围来达到加速的目的。若所有的蛋糕都不能满足某一个人的口,那么可以将其删去
**
waste浪费,对于一块蛋糕,将其分出去一部分满足一些人后,倘若剩余部分连口最小的人都无法满足,那么剩余部分一定不能满足任何人,就属于浪费的部分。若蛋糕有用的部分(总数-浪费)不能满足前mid个人,那么当前二分的答案不可行
**
由于口是递增的,在dfs过程中,可能会遇到这么一种情况,第i个人与第i-1个人的口相同,那么考虑,若不能满足第i-1个人,那么一定不能满足第i个人,进行剪枝
*/#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
using namespace std;
int c[51],p[1100],n,m,b[51];
priority_queue<int> tmp;
bool cmp(int x,int y){
return x>y;
}
bool check(int N){
int i,j,time=1000;
while(time--){//既然拼RP,当然要多rand几遍
for(i=1;i<=n;i++)
b[i]=c[i];//复制一份蛋糕副本
random_shuffle(b+1,b+n+1);//该函数的功能是把一段区间随机打乱
int flag;
for(i=N;i>=1;i--){//这里对要满足的人从大到小枚举
flag=0;
for(j=1;j<=n;j++){//n比较小,暴力枚举蛋糕
if(b[j]>=p[i]){
flag=1;
b[j]-=p[i];
break;
}
}
if(!flag) break;//如果找不到可以满足这个口的蛋糕,说明不行
}
if(flag) return true;
}
return false;
}
int main(){
int i,j,l,r,mid,ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&c[i]);
scanf("%d",&m);
for(i=1;i<=m;i++)
scanf("%d",&p[i]);
sort(p+1,p+m+1);//贪心,口小的人优先取
l=0;r=m;
while(l<=r){//二分
mid=l+r>>1;
if(mid>=0&&check(mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d",ans);
return 0;
} -
02012-07-29 20:35:45@
program ac;
var tot,leave,i,j,n,m,k,l,r,mid,ans,st:longint;
cake,mon,sum:array[0..1024] of longint;
check:boolean;
procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end;
procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=mon[(l+r) div 2];
repeat
while mon[i] -
02010-07-17 23:14:01@
#include
#include
#include
#include
#include#define MAXN 50
#define MAXM 1024using namespace std;
int cmp(const void *a , const void *b)
{
return ( *(int *)a - *(int *)b) ;
}int pack[MAXN + 1] , rail[MAXM + 1] , N , M , total = 0 , sumr[MAXM + 1] , space , Mid , bag[MAXN + 1];
bool Dfsid(int deep , int pos)
{
if (deep total - sumr[Mid]) return false ;
for (int i = pos ; i = rail[deep])
{
bag[i] -= rail[deep] ;
if (bag[i] < rail[1])
space += bag[i] ;
if (rail[deep] == rail[deep - 1])
{
if (Dfsid(deep - 1 , i)) return true ;
}
else
if (Dfsid(deep - 1 , 1)) return true ;
if (bag[i] < rail[1])
space -= bag[i];
bag[i] += rail[deep] ;
}
return false ;
}int main()
{
//freopen("tmp.in","r",stdin);
scanf("%d",&N);
for (int i = 1 ; i 1 ) ;
while (Left 1);
}
else
{
Right = Mid - 1 ;
Mid = ((Left + Right) >> 1);
}
}
printf("%d\n",Mid);
return 0 ;
} -
02010-04-13 21:23:06@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms改得不明不白就过了
-
02010-03-18 21:05:36@
USACO的经典搜索题:
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms -
02009-11-08 15:51:46@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms -
02009-11-06 20:05:17@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms终于秒杀了
2分写错了
BJ -
02009-11-04 17:17:16@
太艰难了,提交11次,只因
-
02009-10-03 20:08:27@
...友情提示。。不能二分。。
-
02009-06-22 13:30:43@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms完美的秒杀,能减就减,注意DFS-ID最好用二分。
附上源代码。program vijos;
var i,j,m,n,min,l,r:integer;
was,tot,x:longint;
boo:boolean;
cake:array[1..50] of longint;
eat,need:array[0..1024] of longint;
procedure sort(s,t:integer);
var i,j:integer;
x,z:longint;
begin
i:=s;
j:=t;
x:=need[(s+t) div 2];
repeat
while need[i] -
02009-05-21 13:02:52@
usaco上交过了
-
02009-05-14 12:04:13@
加二分枚举答案得不到正确解,为什么?
快排加上,最后一个点超时|无输出
换成泡排,0ms
why????? -
02009-03-26 17:52:39@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms -
02009-03-23 20:32:51@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0msAC!
-
02009-03-14 19:38:35@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms -
02008-12-16 13:28:27@
-
02008-12-05 21:06:47@
怎样剪啊
-
02008-11-08 17:37:34@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
二分+dfsid
状态 dfs(r,s,t);
r:蛋糕的搜索下界
s:搜索到第几个人
t:之前浪费的蛋糕量剪枝1:如果第s个人和第s-1个人想的相等,那么这两个人等效,那么我们假定s匹配的蛋糕在s-1的之前,即s-1 的r等于s-1匹配的蛋糕编号
剪枝2:如果之前浪费的蛋糕量t+人的总需求>蛋糕总量,那么剪掉 -
02008-10-26 18:27:18@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
├ 测试数据 11:答案正确... 0ms
├ 测试数据 12:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms艰难的AC历程!
终于做到0ms过拉
真的
剪枝是很有技巧的哦
就是下面的大牛所讲的那样就可以拉