P2905 [USACO08OPEN]农场危机Crisis on the Farm

传送门

DP

设 f [ i ] [ j ] [ k ] 表示已经走了 i 步,向上走了 j 步,向右走了 k 步时能拯救的最多奶牛数(j,k可以为负,表示反向)

设 g [ i ] [ j ] 表示牛向上走 i 步,向右走 j 步后有多少奶牛恰好在草堆上(同样 i , j 可负)

那么 f [ i ] [ j ] [ k ] = max( f [ i-1 ] [ j -1 ] [ k ] , f [ i-1 ] [ j ] [ k-1 ] , f [ i-1 ] [ j+1 ] [ k ] ,f [ i-1 ] [ j ] [ k+1 ]) +g [ j ] [ k ]

因为数组下标不能为负,所以要把坐标集体加上一个 K

为了方便按字典序输出,我们要倒过来推,并且要按字典序的方向来枚举

即从 f [ k ] 推到 f [ 0 ] 枚举方向为 ‘E‘ ‘N‘ ‘S‘ ‘W‘

好像不太好讲,具体还是看代码吧,代码不难的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-1; ch=getchar(); }
    while(ch>=‘0‘&&ch<=‘9‘) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1007,K=31;
int n,m,k;
int xx[4]={1,0,0,-1},yy[4]={0,1,-1,0};
char mp[4]={‘E‘,‘N‘,‘S‘,‘W‘};
int f[K<<1][N][N],g[K<<1][K<<1];
int cow[N][2],hay[N][2];
int main()
{
    n=read(); m=read(); k=read();
    for(int i=1;i<=n;i++) cow[i][0]=read(),cow[i][1]=read();
    for(int i=1;i<=m;i++) hay[i][0]=read(),hay[i][1]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(abs(hay[j][0]-cow[i][0])+abs(hay[j][1]-cow[i][1])<=k)//如果可以到达才计算贡献
                g[hay[j][0]-cow[i][0]+K][hay[j][1]-cow[i][1]+K]++;//预处理g
    for(int i=k;i>=0;i--)
        for(int x=K-i;x<=K+i;x++)
            for(int y=K-i;y<=K+i;y++)//注意大小写K的区别
            {
                for(int o=0;o<4;o++) f[i][x][y]=max(f[i][x][y],f[i+1][x+xx[o]][y+yy[o]]);
                f[i][x][y]+=g[x][y];
            }
    printf("%d\n",f[0][K][K]);
    int posx=K,posy=K;//存当前位置
    for(int i=0;i<k;i++)
    {
        int o;
        for(o=0;o<4;o++) if(f[i][posx][posy]==f[i+1][posx+xx[o]][posy+yy[o]]+g[posx][posy]) break;//如果是从o推过来的就断开
        posx+=xx[o]; posy+=yy[o];
        printf("%c",mp[o]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LLTYYC/p/9860524.html

时间: 2024-10-09 10:43:16

P2905 [USACO08OPEN]农场危机Crisis on the Farm的相关文章

洛谷 P2905 [USACO08OPEN]农场危机Crisis on the Farm(恶心的DP)

P2905 [USACO08OPEN]农场危机Crisis on the Farm 1605: [Usaco2008 Open]Crisis on the Farm 牧场危机 题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场 里还有M(1 < M < 1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有 的牛塔向东南

洛谷P2905 [USACO08OPEN]农场危机Crisis on the Farm

P2905 [USACO08OPEN]农场危机Crisis on the Farm 题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场 里还有M(1 < M < 1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有 的牛塔向东南西北四个方向移动一格. 每一次,当一个牛塔到达了一个草垛所在的格子,牛塔最上方的奶牛就会跳到

洛谷 P2905 [USACO08OPEN]农场危机Crisis on the Farm

题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场 里还有M(1 < M < 1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有 的牛塔向东南西北四个方向移动一格. 每一次,当一个牛塔到达了一个草垛所在的格子,牛塔最上方的奶牛就会跳到草垛上,而且 不再下来,而其他奶牛仍然呈塔状站在草垛所在的格子里.当牛塔只剩一只奶牛

bzoj1621 / P2907 [USACO08OPEN]农场周围的道路Roads Around The Farm

P2907 [USACO08OPEN]农场周围的道路Roads Around The Farm 基础dfs,按题意递归即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define re register 5 using namespace std; 6 int n,k,ans; 7 void dfs(int x){ 8 if(x<=k||((x-k)&1)){//不能有半

每日一水之 luogu2907 [USACO08OPEN]农场周围的道路Roads Around The Farm

题目描述 Farmer John's cows have taken an interest in exploring the territory around the farm. Initially, all N (1 <= N <= 1,000,000,000) cows commence traveling down a road in one big group. Upon encountering a fork in the road, the group sometimes cho

BZOJ1605 [Usaco2008 Open]Crisis on the Farm 牧场危机

标题好长&&我是权限狗,汪汪! 题没看懂的我以为这是一道极难滴题目...然后,然后我就看懂题了. 数据少给了一个条件K <= 30...(没这条件还做个鬼...) f[k, i, j]表示走了k步,x方向移动i,y方向移动j的最大被拯救牛的数量,然后方程就很好写了,略之. (其实是太烦了,不想写) 真是一道很烦的题目...不仅预处理很烦,转移很烦,连输出解也很烦... 1 /*******************************************************

BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机:dp【找转移路径】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1605 题意: 平面直角坐标系中,有n个点,m个标记(坐标范围1~1000). 你可以发出口令,让所有点整体向东.南.西.北四个方向中的任意一个方向移动,口令分别记作'E','S','W','N'. 每当一个点碰到一个标记,则答案+1.(保证初始时没有点在标记上) 你最多可以发出t次口令. 问你答案最大是多少,并输出字典序最小的口令序列. 题解: 表示状态: dp[i][j][k] = m

【USACO 2008 Open Gold】 2.Crisis on the Farm 动规、

题意:输入n.m.p然后是n头牛塔坐标.m个草垛坐标,有p次指令机会. 每次指令可以向上下左右其中一种方向,让所有牛塔都移动一单位. 然后每经过草垛/牛塔次,就有1个权值. 求权值最大值及使权值最大的移动指令序列(字典序最小). 题解:f[i][j][k]表示第i次,移动序列x轴坐标为j,y轴k,最大权值. 然后倒着做以保证字典序. 代码: #include <cstdio> #include <cstring> #include <iostream> #include

经济与技术之四:马克思眼中的无产阶级

经济与技术之四:马克思眼中的无产阶级 马克思用夸张的语言说,无产阶级一无所有.但是却有组织和纪律,他们会成为终结者(资本主义的掘墓人). 他的叙述既象是预言,也象是对远古历史的描述.现代的无产阶级诞生于工业革命中丧失土地的农民,在此之前西方的主要人口仍然是自有土地的农民.而<圣经·创世纪>记载了在埃及法老时代,外来的管理者约瑟(Joseph)是如何在干旱年份帮助法老将埃及所有农民的土地买为己有. 自有土地的农民享受到极为重要的两项权利:基本的收入保障.以及安排生活生产的独立与自由(peasan