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

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

发现总步数$k<=30$,考虑用$k$瞎搞

设$f[u][i][j]$表示已经吹$u$次哨,全体奶牛向右走$i$步,向上走$j$步的最优解

预处理$g[i][j]$表示全体奶牛向右走$i$步,向上走$j$步可以救几只奶牛

显然$f[u][i][j]=max(f[u+1][i+1][j],f[u+1][i-1][j],f[u+1][i][j+1],f[u+1][i][j-1])+g[i][j]$

把方向按字典序,逆推。

end.

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cctype>
 5 #define re register
 6 using namespace std;
 7 void read(int &x){
 8     char c=getchar();x=0;
 9     while(!isdigit(c)) c=getchar();
10     while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
11 }
12 int max(int a,int b){return a>b?a:b;}
13 int abs(int a){return a<0?-a:a;}
14 #define K 31
15 #define N 1001
16 const int d1[4]={-1,0,0,1};
17 const int d2[4]={0,-1,1,0};//方向倒着来因为后面用的是逆推
18 const char d3[4]={'E','N','S','W'};
19 struct node{int x,y;}a[N],b[N];
20 int n,m,k,g[K<<1][K<<1],f[K+1][K<<1][K<<1];//坐标为负的话加上一个maxk转正
21 int main(){
22     read(n);read(m);read(k);
23     for(re int i=1;i<=n;++i) read(a[i].x),read(a[i].y);
24     for(re int i=1;i<=m;++i) read(b[i].x),read(b[i].y);
25     for(re int i=1;i<=n;++i)//预处理g数组
26         for(re int j=1;j<=m;++j)
27             if(abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)<=k)
28                 ++g[a[i].x-b[j].x+K][a[i].y-b[j].y+K];
29     for(re int u=k;u>=0;--u)//逆推好写
30         for(re int i=K-u;i<=K+u;++i)
31             for(re int j=K-u;j<=K+u;++j){
32                 for(int z=0;z<4;++z)
33                     f[u][i][j]=max(f[u][i][j],f[u+1][i+d1[z]][j+d2[z]]);
34                 f[u][i][j]+=g[i][j];
35             }
36     printf("%d
",f[0][K][K]);
37     int x0=K,y0=K;
38     for(re int u=0,z;u<k;++u){
39         for(z=0;z<4;++z)
40             if(f[u][x0][y0]==f[u+1][x0+d1[z]][y0+d2[z]]+g[x0][y0])
41                 break;//发现是这个状态转移来的就跳出
42         printf("%c",d3[z]);
43         x0+=d1[z]; y0+=d2[z];
44     }return 0;
45 }
View Code
原文地址:https://www.cnblogs.com/kafuuchino/p/9856630.html