标签:坐标 字典序 for lib bre bool 范围 重复 include
n<=1000个牛塔,每塔30头牛,m<=1000个地点会使经过的牛塔少一头,K<=30个命令每次使所有牛塔往东西南北某方走一格,求最多损失多少牛并输出字典序最小的方案。
没看到K的范围想不出系列。。由于K<=30,不会出现牛负数的情况,所以直接搜,搜可能会搜到重复,那就记忆化,那不如直接写DP。
f(k,i,j)--走了k步,所有牛相对原来横坐标走了i纵坐标走了j,f(k,i,j)=max f(k-1,四个方向) +s(i,j),其中s(i,j)表示所有牛往右走i格往上走j格(i,j可以是负数)损失的牛,这可以预处理。
最后的方案要字典序最小。由于某个最优状态的i,j是一定的,也就是W-E的数量和N-S的数量是一定的,那后面的W越多,前面的E就越多,字典序就越小,而DP记状态是从后往前走的,所以字典序大的优先选,W->S->N->E,在dp值相同时按这个顺序取就行了。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<math.h> 5 #include<algorithm> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m,K; 10 #define maxn 1011 11 int f[66][66][66],pre[66][66][66],s[66][66]; 12 struct Point{int x,y;}a[maxn];bool mp[maxn][maxn]; 13 char c[66],ss[66];int ls,lss=0; 14 bool check() 15 { 16 if (!lss) return 1; 17 for (int i=ls-1;i>=0;i--) 18 if (c[i]!=ss[i]) return c[i]<ss[i]; 19 return 0; 20 } 21 const int inf=0x3f3f3f3f; 22 int ans=0; 23 int main() 24 { 25 scanf("%d%d%d",&n,&m,&K);int x,y; 26 for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); 27 for (int i=1;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=1; 28 memset(s,0,sizeof(s)); 29 for (int i=-30;i<=30;i++) 30 for (int j=-30;j<=30;j++) 31 { 32 for (int k=1;k<=n;k++) 33 if (a[k].x+i>0 && a[k].x+i<1011 && a[k].y+j>0 && a[k].y+j<1011) 34 if (mp[a[k].x+i][a[k].y+j]) s[i+30][j+30]++; 35 } 36 for (int i=0;i<=60;i++) 37 for (int j=0;j<=60;j++) 38 f[0][i][j]=-inf; 39 f[0][30][30]=0; 40 for (int k=1;k<=K;k++) 41 for (int i=-30;i<=30;i++) 42 for (int j=-30;j<=30;j++) 43 { 44 int x=i+30,y=j+30; 45 f[k][x][y]=-inf; 46 if (x<60 && f[k-1][x+1][y]+s[x][y]>f[k][x][y]) 47 { 48 f[k][x][y]=f[k-1][x+1][y]+s[x][y]; 49 pre[k][x][y]=‘W‘; 50 } 51 if (y<60 && f[k-1][x][y+1]+s[x][y]>f[k][x][y]) 52 { 53 f[k][x][y]=f[k-1][x][y+1]+s[x][y]; 54 pre[k][x][y]=‘S‘; 55 } 56 if (y && f[k-1][x][y-1]+s[x][y]>f[k][x][y]) 57 { 58 f[k][x][y]=f[k-1][x][y-1]+s[x][y]; 59 pre[k][x][y]=‘N‘; 60 } 61 if (x && f[k-1][x-1][y]+s[x][y]>f[k][x][y]) 62 { 63 f[k][x][y]=f[k-1][x-1][y]+s[x][y]; 64 pre[k][x][y]=‘E‘; 65 } 66 if (k==K) ans=max(ans,f[k][x][y]); 67 } 68 printf("%d\n",ans); 69 for (int i=0;i<=60;i++) 70 for (int j=0;j<=60;j++) 71 if (f[K][i][j]==ans) 72 { 73 int t=K,x=i,y=j;ls=0; 74 while (t) 75 { 76 c[ls++]=pre[t][x][y]; 77 switch (pre[t][x][y]) 78 { 79 case ‘W‘:x++;break; 80 case ‘S‘:y++;break; 81 case ‘N‘:y--;break; 82 case ‘E‘:x--;break; 83 } 84 t--; 85 } 86 if (check()) memcpy(ss,c,sizeof(c)),lss=ls; 87 } 88 for (int i=ls-1;i>=0;i--) putchar(ss[i]); 89 return 0; 90 }
注意一下下标不要访问到-1或者61否则会出奇怪错误。
BZOJ1605: [Usaco2008 Open]Crisis on the Farm 牧场危机
标签:坐标 字典序 for lib bre bool 范围 重复 include
原文地址:http://www.cnblogs.com/Blue233333/p/7608148.html