题目:http://acm.hdu.edu.cn/showproblem.php?pid=5402
题意:给定N*M的矩阵,每一格子里面有一个非负整数,求从(1,1)到(n,m)这条路上的和,(每个格子只能走一次,求最大的和)。
分析:官方题解当N为奇数或M为奇数时,可以遍历到所有格子。当N和M都为偶数的时候,那么讲棋盘黑白染色,假设
(1,1)和(n,m)都为黑色,那么这条路径中黑格个数比白格个数多1,而棋盘中黑白格子个数相同,所以必然有一个白格不会被经过,所以选择白格中权值最小的不经过。构造方法是这样,首先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;
}