[USACO18OPEN]Talent Show 解题报告
题目:传送门(洛谷)
这道题可谓刷新了我对0/1分数划分的认识。
之前做过一道最小生成树+0/1分数划分(在我的博客里也有),但这次写的时候没联想到背包问题,考场(noip模拟)上直接上了遗传然后老师多次测评取最低值就只12分了qwq。
如果对0/1分数划分不熟悉的读者可以戳这里阅读相关文章(我觉得我写得还不错(雾))
首先不难发现我们在标操之后,要选出一些牛,这些牛的w(体重)和要大于等于W(体重下限),且他们的评估函数(t-mid*w)之和是否大于等于0决定了mid是大了还是小了(差点写成中考经典病句)。
而怎么选这些牛,就是一个相对经典的背包问题,dp[v]表示用了v的体重,能收集到的最大评估函数的和。
套进背包问题的模板里就行了。
那么代码如下:

#include<iostream> #include<cstdio> #define maxn 300 using namespace std; inline void read(int &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } inline void read(double &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } int N,W; double w[maxn],t[maxn]; double c[maxn],dp[1005]; bool check(double mid) { for(int i=1;i<=N;i++) c[i]=t[i]-mid*w[i]; for(int i=0;i<=W;i++) dp[i]=-0x3f3f3f3f; dp[0]=0; /* for(int v=0;v<=W;v++) { for(int i=1;i<=N;i++) { int tmp=v+w[i]; if(tmp>W) tmp=W; dp[tmp]=max(dp[tmp],dp[v]+c[i]); } }*/ for(int i=1;i<=N;i++) for(int v=W;v>=0;v--) { int tmp=v+w[i]; if(tmp>W) tmp=W; dp[tmp]=max(dp[tmp],dp[v]+c[i]); } // cout<<mid<<" "<<dp[W]<<endl; if(dp[W]>=0.0) return 1; else return 0; } int main() { read(N);read(W); double tw=0,tt=0; for(int i=1;i<=N;i++) { read(w[i]); read(t[i]); tw+=w[i]; tt+=t[i]; } double l=0,r=100005,mid,ans; while(r-l>0.00001) { mid=(r+l)/2; //cout<<l<<" "<<r<<" "; if(check(mid)) l=mid,ans=mid; else r=mid; } ans*=1000; printf("%d",int(ans)); }
--------------------Warning:下面的内容不是正解!!!------------------------
然后我在考场上写的伪遗传在遗传8000次左右可以保证正确,但是时间会高达10s左右。
我提交的版本为了保证时间,只遗传了400代(事实证明一秒内我可以遗传800代甚至更多)。
为了保证时间,我甚至没有写交换。
代码如下:

#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<algorithm> #define maxn 300 #define yep cout<<"yep"<<endl; using namespace std; inline void read(double &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } double N,W; double w[maxn],t[maxn]; struct node{ int u[maxn]; double f; void cal() { double wt=0,tt=0; for(int i=1;i<=N;i++) if(u[i]) wt+=w[i],tt+=t[i]; if(wt<W) f=-1; else f=tt/wt; } friend bool operator < (node a,node b) { return a.f>b.f; } }group[1005]; inline void getnew(int x) { for(int i=1;i<=N;i++) group[x].u[i]=rand()%2; group[x].cal(); } node fuck(node fa,node ma) { int c; node child; for(int i=1;i<=N;i++) { c=rand()%2; if(c) child.u[i]=fa.u[i]; else child.u[i]=ma.u[i]; } child.cal(); return child; } int main() { freopen("talent.in","r",stdin); freopen("talent.out","w",stdout); srand(time(NULL)); read(N);read(W); double tw=0,tt=0; for(int i=1;i<=N;i++){read(w[i]);read(t[i]);} int T=400; for(int i=1;i<=T;i++) { while(group[i].f<=0) getnew(i); } for(int i=1;i<=T;i++) { sort(group+1,group+T+1); for(int i=T/2+1;i<=T;i++) group[i]=fuck(group[i-T/2],group[i-T/2+1]); } sort(group+1,group+T+1); double ans; ans=group[1].f; ans*=1000; printf("%d",int(ans)); }
分类:
解题报告
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)