您的位置:首页 > 其它

USACO月赛题解 第三十讲 动态规划(一)

2014-02-01 14:09 267 查看
汇总见http://blog.csdn.net/qyl916/article/details/12442283

这五个DP题还是很不错的

第6题,方形牛棚 bigbrn

很经典的题目了,没有看题解,自己想了个解法

首先m较小的话可以参考另一篇博客,把点看成边界来做

这道题DP比较好一些

d[i][j]=min(d[i-1][j-1]+1,min( lft[i][j],up[i][j] ) );

lft和up分别表示左方和上方的空间,都能在平方级时间算出

d[i][j]表示以(i,j)为右下角顶点的边长最大值

因此整个算法是平方级的

void setio(string name){
string in_f=name+".in";
string out_f=name+".out";
freopen(in_f.c_str(),"r",stdin);
freopen(out_f.c_str(),"w",stdout);
}
const int maxn=1010;
int d[maxn][maxn],lft[maxn][maxn],up[maxn][maxn],a[maxn][maxn],n,m;
int main()
{
setio("bigbrn");
CLR(a,0);
read2(n,m);
REP(i,m){
int x,y;
read2(x,y);
a[x][y]=1;
}
CLR(lft,0);CLR(up,0);
REP1(i,n)lft[i][1]=a[i][1]==1?-1:0;
REP1(i,n)FOR(j,2,n){
lft[i][j]=a[i][j]==1?-1:lft[i][j-1]+1;
}
REP1(j,n)lft[1][j]=a[1][j]==1?-1:0;
FOR(i,2,n)REP1(j,n){
up[i][j]=a[i][j]==1?-1:up[i-1][j]+1;
}
CLR(d,0);
int ans=0;
REP1(i,n)REP1(j,n){
d[i][j]=min(d[i-1][j-1]+1,min( lft[i][j],up[i][j] ) );
ans=max(ans,d[i][j]);
}
/*REP1(i,n){REP1(j,n)write1(lft[i][j]);PN;}PN;
REP1(i,n){REP1(j,n)write1(up[i][j]);PN;}PN;
REP1(i,n){REP1(j,n)write1(d[i][j]);PN;}*/
writeln(ans+1);
//system("pause");
return 0;
}


第8题 滑雪比赛 bobsled

这题明显是贪心,分类到DP应该是因为用到递推的关系。两个转弯点之间必然是这样的策略:不停加速,直到另一个转弯点“刹不住”,这样就能列出不等式,解出这个区间的最大速度,同时更新下一个转弯点的速度(因为可能不停加速不用刹车).这样就能递推+计算答案了。

但这样做有漏洞:假如两个转弯点之间的距离为1,前一个限速10,后一个限速1,显然第一个点速度只能到2.所以要计算一个弯角的“真限速”,计算方法不难,枚举这个点后面的所有弯角,将这些弯角的限速加上两个弯角之间的距离就行了。什么?这样是平方级的?平方算法有大量重复计算,完全可以变成线性的。

/*
40分 没考虑刹不住的问题
120分 三个小数据不对
仔细一看,终点速度没有算
还是错一个点
大数据出错,INF太小
*/

const LL INF = (LL)1<<50;
struct node{
LL t,s;
};
int cmp(node a, node b){
return a.t < b.t;
}
void setio(string name){
string in_f = name + ".in";
string out_f = name + ".out";
freopen(in_f.c_str(), "r", stdin);
freopen(out_f.c_str(), "w", stdout);
}
node a[100010];
LL d[100010],m[100010],n,l;
int main()
{
setio("bobsled");
scanf("%lld%lld",&l,&n);
REP1(i,n) scanf("%lld%lld",&a[i].t,&a[i].s);
sort(a + 1, a + n + 1, cmp);
a[0].t = 0; a[0].s = 1;
a[n + 1].t = l; a[n + 1].s = INF;
m[n + 1] = INF;
for(LL i = n; i >= 0; i--) m[i]=min(m[i + 1], a[i].s + a[i].t);
LL ans = 0;
d[0]=1;
REP1(i,n){
d[i] = min(min(a[i].s, d[i-1] + a[i].t - a[i - 1].t), m[i + 1] - a[i].t);
ans = max(ans, (a[i].t - a[i - 1].t + d[i] - d[i - 1] ) / 2 + d[i - 1] );
}
ans = max(ans, d
+ l - a
.t);
cout<<ans<<endl;
//while(1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: