这个讲的超好....一定要看...然后看我代码就好懂啦...
http://blog.csdn.net/ta201314/article/details/41287567
各种优化确实非常好....搜索的一道好题...
挂代码:
/* Problem : USACO 4.1.2 栅栏的木料 Author : Robert Yuan 优化解释: 0. 二分+贪心判断可行解 (根据自己设计的贪心算法尽量的得到一个比较靠近正确值的 ans,再后面的搜索的下界就会大大提高) 1. 如果使用的木料与上一块的木料大小相同,那么上一块若没有选前 i块木板,这一块也不要选(1.若是因为前面的太小而不选,那么对于这个也太小 2.若是因为前面的情况已经搜过,那我选择前面的就成了一个已经搜索过的情况) 2. 如果当前需要枚举的木板与上一块木板的大小相同,只选其中最后的那块,理由同上。 3. 如果剩下的木板大小比第一块还小,那么就是属于余料,将所有余料和已经切好的木料减去,剩下的木板长度如果比未切好的 x个木料总长还要小,那么这种状态也是不可行的 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>‘9‘ || ch<‘0‘) ch=getchar(); while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return x; } const int maxn=52; const int maxm=1025; const int INF=0x7f7f7f7f; int n,m,S,ans; int tmp[maxn]; int a[maxn],b[maxm],s[maxm]; bool cmp(const int &a,const int &b){ return a>b; } bool dfs(int x,int last){ if(!x) return true; if(S<s[x]) return false;/*优化 3*/ S-=b[x]; for(int i= x!=ans && b[x]==b[x+1] ? last:1/*优化 1*/;i<=n;i++){ while(i<n && a[i]==a[i+1]) i++;/*优化 2*/ if(a[i]>=b[x]){ a[i]-=b[x]; if(a[i]<b[1]) S-=a[i]; if(dfs(x-1,i)){ if(a[i]<b[1]) S+=a[i]; a[i]+=b[x]; S+=b[x]; return true; } if(a[i]<b[1]) S+=a[i]; a[i]+=b[x]; } } S+=b[x]; return false; } bool check(int m){/*优化 0*/ int Minn,Minx; memcpy(tmp,a,sizeof(a)); for(int i=m;i;i--){ Minn=INF,Minx=-1; for(int j=1;j<=n;j++) if(tmp[j]>=b[i] && Minn>tmp[j]) Minn=tmp[j],Minx=j; if(Minx<0) return false; tmp[Minx]-=b[i]; } return true; } int main(){ n=in(); for(int i=1;i<=n;i++) a[i]=in(),S+=a[i]; m=in(); for(int i=1;i<=m;i++) b[i]=in(); sort(a+1,a+n+1); sort(b+1,b+m+1); for(int i=1;i<=m;i++) s[i]=s[i-1]+b[i]; int l=0,r=m,mid; if(check(r)){ printf("%d",m);return 0; } while(l+1<r){ mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } ans=r; while(dfs(ans,1) && ans<=m) ans++; printf("%d",ans-1); return 0; }
时间: 2024-10-11 09:04:39