收集纸片——dsf

链接:https://ac.nowcoder.com/acm/contest/5713/A
来源:牛客网

题目描述
我们把房间按照笛卡尔坐标系进行建模之后,每个点就有了一个坐标。
假设现在房子里有些纸片需要被收集,收集完纸片你还要回归到原来的位置,你需要制定一个策略来使得自己行走的距离最短。
你只能沿着 x 轴或 y 轴方向移动,从位置 (i,j) 移动到相邻位置 (i+1,j),(i-1,j),(i,j+1) 或 (i,j-1) 距离增加 1。

输入描述:

在第一行中给出一个T,1≤T≤10T, 1 \le T \le 10T,1≤T≤10, 代表测试数据的组数。
对于每组输入,在第一行中给出房间大小,第二行给出你的初始位置。
接下来给出一个正整数 n,1≤n≤10n,1 \le n \le 10n,1≤n≤10 代表纸片的个数。
接下来 n 行,每行一个坐标代表纸片的位置。
保证房间小于 20×2020 \times 2020×20,纸片一定位于房间内。

输出描述:

对于每组输入,在一行中输出答案。
格式参见样例。

示例1
输入
复制

1
10 10
1 1
4
2 3
5 5
9 4
6 5

输出
复制

The shortest path has length 24

一道dfs调了一个多小时,到最后真的是气。在这里记录下来
好好反省!
第一遍写的代码:

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;

struct point
{
	int x; int y;
};

int num, sx, sy, book[11], _min = 9999999, sum;
point pape[11];

void dfs(int, int, int);

int main()
{
	int mapl, mapw, x, y, times, cnt;

	cin >> times;
	while (times--)
	{
		cin >> mapl >> mapw >> sx >> sy >> num;

		int cnt = num, i = 0;
		while (cnt--)
		{
			cin >> x >> y;
			pape[i].x = x; pape[i++].y = y;
		}
		dfs(0, 0, 0);
		cout << "The shortest path has length " << _min;
	}
	return 0;
}

void dfs(int step, int bx, int by)
{
	if (step == num)
	{
		sum += (fabs(sx - bx) + fabs(sy - by));
		if (sum < _min) _min = sum;
		sum -= (fabs(sx - bx) + fabs(sy - by));
		return;
	}

	for (int i = 0; i < num; i++)
	{
		if (book[i] == 0 && step == 0)
		{
			book[i] = 1; sum = 0;
			sum += (fabs(sx - pape[i].x) + fabs(sy - pape[i].y));
			dfs(step + 1, pape[i].x, pape[i].y);
			book[i] = 0; sum -= (fabs(sx - pape[i].x) + fabs(sy - pape[i].y));
		}
		else if(book[i] == 0)
		{
			book[i] = 1;
			sum += (fabs(bx - pape[i].x) + fabs(by - pape[i].y));
			dfs(step + 1, pape[i].x, pape[i].y);
			book[i] = 0; sum -= (fabs(bx - pape[i].x) + fabs(by - pape[i].y));
		}
	}
}

开始做这道题的时候想的使用最短单源路,然后再加上最后回去的路长做,但是题目给出的不是邻接表或邻结矩阵,感觉有些麻烦就没有这样写。
然后就想到了搜索,选择了dfs。开始时设计的时维持三个参数:步数,上一步的下x, y(用来求路径长度),但是在写的时候发现每一次退出的时候还要再减去这次走的路的长度(这个超级容易漏掉,尤其是算完总长的的时候!!!),否则部署会一直增加,就很麻烦。还要在搜索的时候判断是否是第一次,因为一定要从起点开始!。
第一次设计的要维护的参数不是很好,在网上浏览题解后有了如下设计:

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;

struct point
{
	int x; int y;
};

int num, sx, sy, fx, fy, book[11], _min = 9999999;
point pape[11];

void dfs(int bx, int by, int step, int length)
{
	if (length > _min) return;

	if (step == num)
	{
		if (length < _min)
		{
			_min = length;
			fx = bx; fy = by;
		}
		return;
	}

	for (int i = 0; i < num; i++)
		if (book[i] == 0)
		{
			book[i] = 1;
			dfs(pape[i].x, pape[i].y, step + 1, length + fabs(bx - pape[i].x) + fabs(by - pape[i].y));
			book[i] = 0;
		}
}

int main()
{
	int mapl, mapw, x, y, times, cnt;

	cin >> times;
	while (times--)
	{
		cin >> mapl >> mapw >> sx >> sy >> num;

		int cnt = num, i = 0;
		while (cnt--)
		{
			cin >> x >> y;
			pape[i].x = x; pape[i++].y = y;
		}
		dfs(sx, sy, 0, 0);
		cout << "The shortest path has length " << _min + fabs(sx - fx) + fabs(sy - fy);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值