hdu 5402 Travelling Salesman Problem (构造)

题目: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

hdu 5402 Travelling Salesman Problem (构造)的相关文章

HDU 5402 Travelling Salesman Problem (构造)(好题)

大致题意:n*m的非负数矩阵,从(1,1) 只能向四面走,一直走到(n,m)为终点,路径的权就是数的和,输出一条权值最大的路径方案 思路:由于这是非负数,要是有负数就是神题了,要是n,m中有一个是奇数,显然可以遍历,要是有一个偶数,可以画图发现,把图染成二分图后,(1,1)为黑色,总能有一种构造方式可以只绕过任何一个白色的点,然后再遍历其他点,而绕过黑色的点必然还要绕过两个白色点才能遍历全部点,这是画图发现的,所以找一个权值最小的白色点绕过就可以了, 题解给出了证明: 如果n,mn,m都为偶数,

构造 - HDU 5402 Travelling Salesman Problem

Travelling Salesman Problem Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5402 Mean: 现有一个n*m的迷宫,每一个格子都有一个非负整数,从迷宫的左上角(1,1)到迷宫的右下角(n,m),并且使得他走过的路径的整数之和最大,问最大和为多少以及他走的路径. analyse: 首先,因为每个格子都是非负整数,而且规定每个格子只能走一次,所以为了使和尽可能大,必定是走的格子数越多越好.这样我们就需

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): 568    Accepted Submission(s): 200 Special Judge Problem Description Teacher Mai is in a maze with n rows and m colum

HDU 5402 Travelling Salesman Problem(棋盘染色 构造 多校啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5402 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 corn

hdu 5402 Travelling Salesman Problem

题意:从一个方格的左上角走到右下角,拿起经过的全部数字,且每一个方格最多仅仅能走一次,问,终于到达右下角时,sum最大是多少. 做法:--非常显然构造了 首先假设nn为奇数或者mm为奇数,那么显然能够遍历整个棋盘. 如果n,mn,m都为偶数,那么将棋盘黑白染色,如果(1,1)(1,1)和(n,m)(n,m)都为黑色,那么这条路径中黑格个数比白格个数多11.而棋盘中黑白格子个数同样.所以必定有一个白格不会被经过,所以选择白格中权值最小的不经过. 构造方法是这样.首先RRRRDLLLLD这种路径走到

hdu 5402 Travelling Salesman Problem (技巧) 未写完-------------------------------

题意:给一个n*m的矩阵,每个格子中有一个数字,每个格子仅可以走一次,问从(1,1)走到(n,m) 的路径点权之和. 思路: 想了挺久,就是有个问题不能短时间证明,所以不敢下手. 显然只要n和m其中一个是奇数,逐行/列绕就可以到达终点,可是恰好都是偶数呢?由于绕不到,那至少得舍弃1个,但是弃哪个比较好?况且有些格子是弃不了的(画4*4的模拟就知道了). 通过画图可以知道(自己绕!),行号+列号为奇数的格子都是可以舍弃的,而且可以保证其他所有格子都能走一遍到终点(无论是从行/列为单位来绕,这个图都

HDU 5402 Travelling Salesman Problem (MUT#9 暴力模拟)

[题目链接]click here~~ [题目大意]:走方格,从[1,1]到[n,m],求中间过程得到的数字和最大,并且输出路径 [思路]: 如果n和m里面有一个是奇数那么全部走遍就好了. 否则要找一个最小的点不要,这个点的坐标要满足x+y是奇数 如果不是的话,舍弃该点一定会导致另外一个点也走不到. 然后找到这个点,暴力输出路径即可. 代码: #include <bits/stdc++.h> using namespace std; const int N=105; typedef long l

hdu(5402)——Travelling Salesman Problem(模拟题)

啊...这道题我一开始的想法是dp,因为我们要求的是在这个区间中和的最大值. 但是没想到只要暴力就好了. 这道题用到了一个著名的想法是:黑白棋盘染色问题. 题意: 现在给你一个n*m的矩阵,然后告诉你每个矩阵中的数字,然后现在要从左上角走到右下角,然后问你所能获得的数字和的最大值是多少.当然,你只能往四个方向走,而且每个点只能走一次.并且叫你输出路径. 思路: 这里我分了三种情况. 1)首先当行或者列数都是1的时候,那么我们就只可能有一种走法(横着走或者是竖着走)然后获取所有的数值. 2)当行数

HDOJ 5402 Travelling Salesman Problem 模拟

行数或列数为奇数就能够所有走完. 行数和列数都是偶数,能够选择空出一个(x+y)为奇数的点. 假设要空出一个(x+y)为偶数的点,则必须空出其它(x+y)为奇数的点 Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 747    Accepted Submission(s): 272