BZOJ1082: [SCOI2005]栅栏
2017-05-25 09:14
211 查看
易水人去,明月如霜。
买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
最多能够得到多少他所需要的木板。
度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30
思路:直接暴搜,但是加的优化很多,下面列举一下主要的
1.对现有和所需排序,之后搜索的时候一定是先满足小的需求再满足大的需求(贪心思路)
2.对于现有木材中的max,凡是需求中大于max的,都可以直接扔掉不要,因为它们一定切不出来(同样可用于需求中的min)
3.二分,在0-m中二分判断是否可以达到mid,一定是从1-mid块木板(已升序排列)中切最优
4.如果剩余木材小于还没切但要切的需求总量,就返回
5.如果是相同的需求,我们可以让它们强制有序,即i需求用j木材切,若i+1需求与i相同,则i+1一定用大于等于j木材切
还有一些po主自己加的,不知道能优化多少
6.随便搞个贪心,算一下浪费量trash,在搜索中可以进行判断,如果浪费更多了那必定不优于最初的贪心(代码中的实现不尽人意,应该还能在精进一下,比如每次算出更优答案时可以更新浪费量trash)
7.接上面,顺便算出最初贪心时能切minn块,然后答案一定是在minn-m间,比0-m要优
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int read()
{
char ch;int s=0,f=1;ch=getchar();
while(ch>'9'||ch<'0') { if(ch=='-') f*=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=s*10+ch-48,ch=getchar();
return s*f;
}
bool flag;
int n,m,mid;
int a[55],b[1005],bl[1005];
ll sa;
int sb[1005];
void dfs(int ak,int bk,int w)
{
if(bk==0)flag=1;
while(ak<=n&&a[ak]<b[1]){w+=a[ak];ak++;}
if(flag||ak>n)return;
if(w+sb[mid]>sa)return;
int t=ak,t1=ak,t2=bk,t3=w;
if(b[bk]==b[bk+1]&&bk!=mid)t=bl[bk+1];
for(int i=t;i<=n;i++)
if(a[i]>=b[bk])
{
bl[bk]=i;a[i]-=b[bk];
bk--;
dfs(ak,bk,w);
ak=t1;bk=t2;w=t3;a[i]+=b[t2];
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
m=read();
for(int i=1;i<=m;i++)b[i]=read();
sort(a+1,a+n+1);
sort(b+1,b+m+1);
while(b[m]>a
)m--;
int tot=0;
for(int i=1;i<=n;i++)
if(a[i]>b[1])a[++tot]=a[i];
n=tot;
for(int i=1;i<=n;i++)sa+=a[i];
for(int i=1;i<=m;i++)sb[i]=sb[i-1]+b[i];
int l=1,r=m,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
flag=0;dfs(1,mid,0);
if(flag)ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
한국어 中文 فارسی English ไทย
版权所有 ©2008-2012 大视野在线测评 |
湘ICP备13009380号 |
站长统计
Based on opensource project
hustoj.
Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
最多能够得到多少他所需要的木板。
Input
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。Sample Input
430
40
50
25
10
15
16
17
18
19
20
21
25
24
30
Sample Output
7HINT
25切出 21 30切出 20 40切出 19、18 50切出 15、16、17思路:直接暴搜,但是加的优化很多,下面列举一下主要的
1.对现有和所需排序,之后搜索的时候一定是先满足小的需求再满足大的需求(贪心思路)
2.对于现有木材中的max,凡是需求中大于max的,都可以直接扔掉不要,因为它们一定切不出来(同样可用于需求中的min)
3.二分,在0-m中二分判断是否可以达到mid,一定是从1-mid块木板(已升序排列)中切最优
4.如果剩余木材小于还没切但要切的需求总量,就返回
5.如果是相同的需求,我们可以让它们强制有序,即i需求用j木材切,若i+1需求与i相同,则i+1一定用大于等于j木材切
还有一些po主自己加的,不知道能优化多少
6.随便搞个贪心,算一下浪费量trash,在搜索中可以进行判断,如果浪费更多了那必定不优于最初的贪心(代码中的实现不尽人意,应该还能在精进一下,比如每次算出更优答案时可以更新浪费量trash)
7.接上面,顺便算出最初贪心时能切minn块,然后答案一定是在minn-m间,比0-m要优
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int read()
{
char ch;int s=0,f=1;ch=getchar();
while(ch>'9'||ch<'0') { if(ch=='-') f*=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=s*10+ch-48,ch=getchar();
return s*f;
}
bool flag;
int n,m,mid;
int a[55],b[1005],bl[1005];
ll sa;
int sb[1005];
void dfs(int ak,int bk,int w)
{
if(bk==0)flag=1;
while(ak<=n&&a[ak]<b[1]){w+=a[ak];ak++;}
if(flag||ak>n)return;
if(w+sb[mid]>sa)return;
int t=ak,t1=ak,t2=bk,t3=w;
if(b[bk]==b[bk+1]&&bk!=mid)t=bl[bk+1];
for(int i=t;i<=n;i++)
if(a[i]>=b[bk])
{
bl[bk]=i;a[i]-=b[bk];
bk--;
dfs(ak,bk,w);
ak=t1;bk=t2;w=t3;a[i]+=b[t2];
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
m=read();
for(int i=1;i<=m;i++)b[i]=read();
sort(a+1,a+n+1);
sort(b+1,b+m+1);
while(b[m]>a
)m--;
int tot=0;
for(int i=1;i<=n;i++)
if(a[i]>b[1])a[++tot]=a[i];
n=tot;
for(int i=1;i<=n;i++)sa+=a[i];
for(int i=1;i<=m;i++)sb[i]=sb[i-1]+b[i];
int l=1,r=m,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
flag=0;dfs(1,mid,0);
if(flag)ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
한국어 中文 فارسی English ไทย
版权所有 ©2008-2012 大视野在线测评 |
湘ICP备13009380号 |
站长统计
Based on opensource project
hustoj.
相关文章推荐
- BZOJ1082: [SCOI2005]栅栏
- [BZOJ1082][SCOI2005]栅栏 二分+搜索减枝
- [BZOJ1082][SCOI2005]栅栏
- bzoj1082: [SCOI2005]栅栏
- BZOJ 1082 [SCOI2005]栅栏 二分+DFS
- 【BZOJ1082】【SCOI2005】栅栏
- bzoj1082[SCOI2005]栅栏
- 【BZOJ】1082: [SCOI2005]栅栏(二分+dfs)
- bzoj 1082: [SCOI2005]栅栏【二分+dfs】
- 【bzoj1082】[SCOI2005]栅栏
- BZOJ1082 [SCOI2005]栅栏
- BZOJ1082: [SCOI2005]栅栏
- bzoj 1082: [SCOI2005]栅栏(二分+DFS)
- 【bzoj1082】 SCOI2005—栅栏
- BZOJ 1082: [SCOI2005]栅栏 DFS,剪枝,二分答案
- 【bzoj1082】 SCOI2005 栅栏 二分+搜索
- BZOJ1082: [SCOI2005]栅栏 题解
- [BZOJ1082][SCOI2005]栅栏
- 【BZOJ 1082】 [SCOI2005]栅栏
- [BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】