题目:http://acm.hdu.edu.cn/showproblem.php?pid=5402
题意:给定N*M的矩阵,每一格子里面有一个非负整数,求从(1,1)到(n,m)这条路上的和,(每个格子只能走一次,求最大的和)。
分析:官方题解当N为奇数或M为奇数时,可以遍历到所有格子。当N和M都为偶数的时候,那么讲棋盘黑白染色,假设
(1,1)(1,1)和(n,m)(n,m)都为黑色,那么这条路径中黑格个数比白格个数多11,而棋盘中黑白格子个数相同,所以必然有一个白格不会被经过,所以选择白格中权值最小的不经过。构造方法是这样,首先RRRRDLLLLD这样的路径走到这个格子所在行或者上一行,然后DRUR这样走到这个格子的所在列或者前一列,然后绕过这个格子。然后走完这两行,接着按LLLLDRRRR这样的路径往下走。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <string> using namespace std; const int maxn = 1e3; int G[maxn][maxn]; int Sum,move_x,move_y; void CoverRow(int n,int m) //行 { int cur_x=1,cur_y=1; while(true) { while(cur_y+1<=m) { cur_y++; putchar('R'); if(cur_x==n && cur_y==m) return ; } if(cur_x==n && cur_y==m) return ; putchar('D'); cur_x++; while(cur_y-1>=1) { cur_y--; putchar('L'); } putchar('D'); cur_x++; } } void CoverColumn(int n,int m) //列 { int cur_x=1,cur_y=1; while(true) { while(cur_x+1<=n) { cur_x++; putchar('D'); if(cur_x==n && cur_y==m) return ; } if(cur_x==n && cur_y==m) return ; putchar('R'); cur_y++; while(cur_x-1>=1) { cur_x--; putchar('U'); } putchar('R'); cur_y++; } } void solve(int n,int m) { int cur_x=1,cur_y=1; while(cur_x+1<move_x) { while(cur_y+1<=m) { cur_y++; putchar('R'); } cur_x++; putchar('D'); if(cur_x+1<move_x) { while(cur_y-1>=1) { cur_y--; putchar('L'); } cur_x++; putchar('D'); } } // printf("cur :%d %d\n",cur_x,cur_y); // system("pause"); if(cur_y==1) { string str("#DRU"); int len=(m-2)/2,i; for(i=1;i<=len;i++) str+="RDRU"; bool fg=false; for(i=1;i<str.size();i++) { if(fg) { if(str[i]=='D') { putchar('U'); cur_x--; } else if(str[i]=='U') { putchar('D'); cur_x++; } else { putchar(str[i]); cur_y++; } } else { if(str[i]=='R') { cur_y++; putchar('R'); } else if(str[i]=='D') { cur_x++; if(cur_x==move_x && cur_y==move_y) { cur_x--; fg=true; continue ; } putchar('D'); } else { cur_x--; if(cur_x==move_x && cur_y==move_y) { cur_x++; fg=true; continue ; } putchar('U'); } } } } else { string str("#DLU"); int len=(m-2)/2,i; for(i=1;i<=len;i++) str+="LDLU"; bool fg=false; for(i=1;i<str.size();i++) { if(fg) { if(str[i]=='L') { putchar('L'); cur_y--; } else if(str[i]=='D') { putchar('U'); cur_x--; } else { putchar('D'); cur_x++; } } else { if(str[i]=='L') { cur_y--; putchar('L'); } else if(str[i]=='D') { cur_x++; if(cur_x==move_x && cur_y==move_y) { cur_x--; fg=true; continue ; } putchar('D'); } else { cur_x--; if(cur_x==move_x && cur_y==move_y) { cur_x++; fg=true; continue ; } putchar('U'); } } } } // printf("Part2 cur:%d %d\n",cur_x,cur_y); // system("pause"); if(cur_x==n && cur_y==m) { putchar('\n'); return ; } cur_x++; putchar('D'); while(true) { if(cur_y==1) { for(int i=2;i<=m;i++) { cur_y++; putchar('R'); } if(cur_x==n && cur_y==m) { putchar('\n'); return ; } cur_x++; putchar('D'); } else { for(int i=2;i<=m;i++) { cur_y--; putchar('L'); } cur_x++; putchar('D'); } } putchar('\n'); } void getmove(int n,int m) { int Min=2e9,i,j; for(i=1;i<=n;i+=2) { for(j=2;j<=m;j+=2) { if(G[i][j]<Min) { Min=G[i][j]; move_x=i; move_y=j; } } } for(i=2;i<=n;i+=2) { for(j=1;j<=m;j+=2) { if(G[i][j]<Min) { Min=G[i][j]; move_x=i; move_y=j; } } } Sum-=Min; } int main() { int i,j,m,n; while(scanf("%d%d",&n,&m)==2) { Sum=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&G[i][j]); Sum+=G[i][j]; } if(n&1 || m&1) { printf("%d\n",Sum); if(n&1) CoverRow(n,m); else CoverColumn(n,m); putchar('\n'); continue ; } getmove(n,m); printf("%d\n",Sum); // printf("move : %d %d\n",move_x,move_y); // system("pause"); solve(n,m); } return 0; }
时间: 2024-10-14 17:21:18