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

来源:互联网 发布:淘宝手机端购买流量 编辑:程序博客网 时间:2024/05/21 04:16

汇总见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[n] + l - a[n].t);    cout<<ans<<endl;    //while(1);    return 0;}

0 0
原创粉丝点击