21/7/2012 ICPC培训 第六天
今天本来安排刷DP的,可是各种不懂呀!!!勉强刷出两道题!
眼看没做出题,还是刷两道二分查找吧。
其他的就是讲解了昨天下午的比赛题目。各种思路,搞得我甚是膜拜。每种思路都很简洁,
把需要解决的问题抽象的很好很好。为啥我就不能想出来呢???无语吆。。。
不过膜拜归膜拜,有了思路得在这两天把没做出来的几题刷了。
最后,晚上,张浩然同学给我们简单介绍了下STL。
还是来讲讲我做的题吧。
第一题(HDU1881)
这题是01背包的变形。思路和01背包很像。
我搞不明白为什么要先对各个bg按照离校时间由小到大排序,然后再用01背包的方法解决?
期待,看到博文的大神赐教哇。。。
代码:
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int MAX=31;int dp[MAX*MAX*2];int maxTime,n;struct node{ int h,l,t; bool operator < (const node &tmp) const { return t<tmp.t; } }temp[MAX];//bool cmp(node a,node b)//{// return a.t<b.t;//}void input(){ maxTime=0; for(int i=0;i<n;i++) { cin>>temp[i].h>>temp[i].l>>temp[i].t; maxTime=maxTime>temp[i].t?maxTime:temp[i].t; }}void pack(){ memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) { for(int j=maxTime;j>=temp[i].l;j--) { if(temp[i].t>=j && dp[j]<dp[j-temp[i].l]+temp[i].h) { dp[j]=dp[j-temp[i].l]+temp[i].h; } } } int result=-1; for(int k=0;k<=maxTime;k++) { result=result>dp[k]?result:dp[k]; } cout<<result<<endl; } int main(){ while(cin>>n,n>=0) { input(); //sort(temp,temp+n,cmp); sort(temp,temp+n); pack(); } return 0;}
第二题(HDU2141)
看到这类题,爆搜很通用,前提是数据量不太大。这题显然爆搜超时。
如何优化呢?可以对C二分,也可以对A+B二分。对A+B二分时间性能更好点。
代码:
#include<iostream>#include<cstring>#include<algorithm> using namespace std;const int MAX=500;int a,b,c,quary,ans,cas=1;int A[MAX],B[MAX],C[MAX],D[MAX*MAX];bool flag; void input(){ int i; for(i=0;i<a;i++) { scanf("%d",&A[i]); } for(i=0;i<b;i++) { scanf("%d",&B[i]); } for(i=0;i<c;i++) { scanf("%d",&C[i]); }}void preDeal(){ int k=0; for(int i=0;i<a;i++) { for(int j=0;j<b;j++) { D[k++]=A[i]+B[j]; } } sort(D,D+k); }void binSearch(int low,int high){ int mid=(low+high)/2; if(low+1==high && D[mid]!=ans) return; if(D[mid]==ans) { flag=true; return; } else if(D[mid]<ans) { binSearch(mid,high); } else { binSearch(low,mid); }} void deal(){ scanf("%d",&quary); printf("Case %d:\n",cas++); int temp,i,j; for(i=0;i<quary;i++) { scanf("%d",&temp); flag=false; for(j=0;j<c;j++) { if(flag) break; ans=temp-C[j]; binSearch(0,a*b-1); } if(flag) printf("YES\n"); else printf("NO\n"); }} int main(){ while(cin>>a>>b>>c) { input(); preDeal(); deal(); } return 0;}
第三题(HDU2199)
这题是解方程。
这个方程在0—100范围内明显是递增的。所以,输入的y太大或太小就可以直接判断是No soulution!了。
另外,这题不能1Y的原因在于你选择的精度大小。刚开始我用的精度是1e-7,结果就TLE了。然后改成
1e-5,0MS过了。
代码:
#include<iostream>#include<iomanip> #include<cmath>using namespace std;const double accurate=1e-5; //这里精度写成1e-7,TLE了 double x,y; double calculate(double x){ return 8*pow(x,4) + 7*pow(x,3) + 2*pow(x,2) + 3*x + 6 ;}void binSearch(double low,double high){ double mid=(low+high)*1.0/2.0; if(fabs(calculate(mid)-y)<=accurate) { x=mid; return; } else if(calculate(mid)<y) { binSearch(mid,high); } else { binSearch(low,mid); }} int main(){ int cas; scanf("%d",&cas); while(cas--) { scanf("%lf",&y); if(y<6 || y>807020306) { printf("No solution!\n"); continue; } binSearch(0,100); cout<<setiosflags(ios::fixed)<<setprecision(4)<<x<<endl; } return 0;}
最后一题是昨天下午比赛的一道DP题,在同学的帮助下找到状态转移方程了!
然后晚上出题的同学又讲了一种完全不同构造方程的思路。可见的是DP借助数组来表达状态,
你给数组赋予不同的含义也就可以找到不同大方程。
DP很抽象,得加强练习了。。。