hdu 5402 Travelling Salesman Problem(构造+模拟)

Travelling Salesman Problem

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 872    Accepted Submission(s): 316
Special Judge

Problem Description
Teacher Mai is in a maze with n rows and m columns. There is a non-negative number in each cell. Teacher Mai wants to walk from the top left corner (1,1) to the bottom right corner (n,m). He can choose one direction and walk to this adjacent cell. However, he can't go out of the maze, and he can't visit a cell more than once.
Teacher Mai wants to maximize the sum of numbers in his path. And you need to print this path.

Input

There are multiple test cases.
For each test case, the first line contains two numbers n,m(1≤n,m≤100,n∗m≥2).
In following n lines, each line contains m numbers. The j-th number in the i-th line means the number in the cell (i,j). Every number in the cell is not more than 104.


Output
For each test case, in the first line, you should print the maximum sum.
In the next line you should print a string consisting of "L","R","U" and "D", which represents the path you find. If you are in the cell
(x,y) , "L" means you walk to cell (x,y1) , "R" means you walk to cell (x,y+1) , "U" means you walk to cell (x1,y) , "D" means you walk to cell (x+1,y) .

Sample Input
3 3
2 3 3
3 3 3
3 3 2

Sample Output
25
RRDLLDRR

题目大意就是给你一个都是非负元的矩阵,从左上走到右下要求所走过的数字之和最大。
题目很简单,写起来并不简单。
做法就是走过的格子数越多越好。行和列只要有一个是奇数就能够将格子走完,这个不用说了。
难点就在于行和列都是偶数,这就是黑白棋盘问题。
如果把棋盘中的每个格子都给一个属性,行+列能被2整除的叫做黑格,不能被2整除的叫白格,就构造出来像国际象棋一样的棋盘。(可以画一画看看)
我们知道共有偶数个格子,而且左上和右下的格子都是相同颜色的黑格,因此要想尽可能的多走格子的话,这条路径上的黑格必定和白格的数量相差 1 。
因此最少最少有一个格子没有走,而且一定要是白格(想想为什么!)。所以要找出所有的白格中最小的那个选择不走。

选择格子的问题结束了,然后就是怎么走的问题,这里借鉴了别人的意见,然后代码量减少了一半(不得不佩服别人,自己还是图样图森破)。
不管怎么样先左右左右的走到那个不走格子的上一行或者上两行,这个就取决于这个点横坐标的奇偶性了。

偶数行的情况:
奇数行的情况:
这样只要特殊处理下不走的格子的那两行的走法,然后其余行都是左右左右的走就可以了。

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

#define SIZE 500
using namespace std;
#define INF 0xf3f3f3
typedef long long ll;

ll n,m;
ll ans,minn;
ll Map[SIZE][SIZE];
int x,y;
void input()
{
    minn = INF;
    ans = 0;
    for(int i = 0 ; i < n ; i ++)
    {
        for(int j = 0 ; j < m ; j ++)
        {
            scanf("%I64d",&Map[i][j]);
            ans += Map[i][j];
            if((i+j)%2)     //假定首尾为黑格子,则删除白格子中值最小的那个
            {
                if((i==0&&j==0) || (i==n-1 && j==m-1))
                    continue;
                if(minn >= Map[i][j])
                {
                    minn = Map[i][j];
                    x = i;
                    y = j;
                }
            }
        }
    }
}

void work3(int n,int m,int r,int c)
{
	int len=r/2;
	for(int i=0;i<len;i++)
	{
		for(int j=0;j<m-1;j++)
			putchar('R');
		putchar('D');
		for(int j=0;j<m-1;j++)
			putchar('L');
		putchar('D');
	}
	len=c/2;
	for(int i=0;i<len;i++)
		printf("DRUR");
	if(r&1)
		printf("RD");
	else
		printf("DR");
	len=m/2;
	for(int i=c/2+1;i<len;i++)
		printf("RURD");
	len=n/2;
	for(int i=r/2+1;i<len;i++)
	{
		putchar('D');
		for(int j=0;j<m-1;j++)
			putchar('L');
		putchar('D');
		for(int j=0;j<m-1;j++)
			putchar('R');
	}
}
int main()
{
    freopen("in6.txt","r",stdin);
    freopen("out6.txt","w",stdout);
    while(scanf("%I64d%I64d",&n,&m)!=EOF)
    {
        input();
        if(n%2==0&&m%2==0)
        {
            ans -= minn;
            printf("%I64d\n",ans);
            work3(n,m,x,y);
            printf("\n");
        }
        else if(n%2==0&&m%2!=0)     //偶数行、奇数列 竖着走
        {
            printf("%I64d\n",ans);
            for(int i = 0 ; i < m ; i ++)
            {
                if(i%2 == 0)     //偶数列往下走 (从第0行开始,所以从偶数行开始计)
                {
                    for(int j = 0 ; j < n-1 ; j ++)
                        printf("D");
                    if(i != m-1)    //最后一个点不走
                        printf("R");
                }
                else        //奇数列往上走
                {
                    for(int j = 0 ; j < n-1 ; j ++)
                        printf("U");
                    printf("R");
                }
            }
            printf("\n");
        }
        else        //奇数行、偶数列 横着走 (奇数列、奇数行随便走)
        {
            printf("%I64d\n",ans);
            for(int i = 0 ; i < n; i ++)
            {
                if(i%2 == 0)     //偶数行往右走
                {
                    for(int j = 0 ; j < m-1 ; j ++)
                        printf("R");
                    if(i!=n-1)
                        printf("D");
                }
                else
                {
                    for(int j = 0 ; j < m-1 ; j ++)
                        printf("L");
                    printf("D");
                }
            }
            printf("\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值