今天本来安排刷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很抽象,得加强练习了。。。