洛谷P1713 麦当劳叔叔的难题

题目描述

话说我们铭铭小朋友成功的回答了爸爸的问题,自然少不了要去索要些奖励,抠门的爸爸一看报纸,嘿,门口的麦当劳在搞活动,还有免费午餐哦,不过前提条件:得正确回答麦当劳叔叔的问题。

问题是这样描述的:

“我面前有很多个小朋友,我希望你帮我找到一个最聪明的小朋友。我心目中最聪明的就是第一个跑进麦当劳大门的,我希望你帮我找出最聪明和最不聪明的小朋友,可能的最大的到达时间差。但是,小朋友只能按照一个特殊的规则前进。小朋友面前有一个 𝑛×𝑛n×n 的格子矩阵,左下角的格子是起点,右上角的格子是大门。每个孩子每秒可以走向 上、下、左、右 前进一个格子,每个格子只能经过一次。但矩阵中间有一些障碍区,不能通过,只能绕过。”

例如,4×44×4 的矩阵,格子 (1,1),(2,3),(4,2)(1,1),(2,3),(4,2) 为障碍区,黑格子就是一条可行的路线。时间为 77。

输入格式

第一行为两个整数 𝑛,𝑚n,m。

第二至第 𝑚+1m+1 行里,每行描述一个障碍区。用两个整数表示 𝑥,𝑦x,y。

输出格式

仅一行,那个最大的时间差。

输入输出样例

输入 #1

4 3
1 1
2 3
4 2

输出 #1

4

说明/提示

2≤𝑛≤102≤n≤10,0≤𝑚≤1000≤m≤100,1≤𝑥,𝑦≤𝑛1≤x,y≤n。

code:

#include <bits/stdc++.h>

using pii = std::pair<int,int>;
const int inf = 1e7;

int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};

int n,m,dis[12][12],ban[12][12];

std::map< std::vector<int> , int >dp[12][12];	

std::vector<int> process(std::vector<int>S) {
	int cnt = 1;
	int vis[30] = {0};
	for (int i = 1; i <= n + 1; ++ i) {
		if (S[i] == 0 || S[i] == 1) continue;
		if (!vis[S[i]]) { vis[S[i]] = ++cnt; S[i] = cnt; }
		else S[i] = vis[S[i]];
	} return S;
}
std::vector<int> shift(std::vector<int>S){ for (int i = 1; i <= n; ++ i) S[i] = S[i+1]; S[n+1] = 0; return S; }
std::vector<int> trans(std::vector<int>S,int i) { std::swap(S[i],S[i+1]); return S; }
std::vector<int> create(std::vector<int>S,int i) { S[i] = S[i+1] = 20; return process(S); }
std::vector<int> merge(std::vector<int>S,int i) {
	int p = S[i], q = S[i+1], flag = 20;
	if (p == 1 || q == 1) flag = 1;
	for (int i = 1; i <= n + 1; ++ i) if (S[i] == p || S[i] == q) S[i] = flag;
	S[i] = S[i+1] = 0;
	return process(S);
}

int main() {
	
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= m; ++ i) {
		int x,y;
		scanf("%d%d",&x,&y);
		ban[x][y] = 1;
		assert( not ( (x == 1 && y == n)  or (x == n && y == 1) ) );
	}
	
	auto bfs = [&]() {
		std::memset(dis,-1,sizeof(dis));
		std::queue< pii >q;
		q.push( { 1,n } );
		dis[1][n] = 0;
		while (q.size()) {
			auto u = q.front(); q.pop();
			int x = u.first, y = u.second;
			for (int i = 0; i < 4; ++ i) {
				int x1 = x + dx[i], y1 = y + dy[i];
				if (x1 < 1 || x1 > n || y1 < 1 || y1 > n || dis[x1][y1] != -1 || ban[x1][y1]) continue;
				dis[x1][y1] = dis[x][y] + 1;
				q.push( { x1,y1 } );
			}
		} 
	};  bfs();
	
	std::vector<int>v(n+2);
	v[n+1] = 1; dp[1][n-1][v] = 1;
	v[n+1] = 0; v[n] = 1; dp[1][n-1][v] = 1;
	
	for (int i = 1; i <= n; ++ i) {
		for (int j = n - (i == 1); j >= 1; j --) {
			for (auto P:dp[i][j]) {
				auto S = P.first; int v = P.second;
				int p = S[j], q = S[j+1];
				if (p == 0 && q == 0) dp[i][j-1][S] = std::max(dp[i][j-1][S],v);
				if (ban[i][j]) continue;
				if (p == 0 && q == 0) {
					auto T = create(S,j);
					dp[i][j-1][T] = std::max(dp[i][j-1][T],v + 1);
				}
				if ((p != 0) + (q != 0) == 1) {
					dp[i][j-1][S] = std::max(dp[i][j-1][S],v + 1);
					auto T = trans(S,j);
					dp[i][j-1][T] = std::max(dp[i][j-1][T],v + 1);
				}
				if (p && q && p != q) {
					auto T = merge(S,j);
					dp[i][j-1][T] = std::max(dp[i][j-1][T],v + 1);
				}
			}
		} for (auto P:dp[i][0]) {
			auto S = P.first; int v = P.second;
			if (S[1] == 0) dp[i+1][n][shift(S)] = dp[i][0][S];
		}
	}
	std::vector<int>S1(n+2),S2(n+2);
	S1[1] = 1; S2[2] = 1;
	printf("%d",std::max(dp[n][1][S1],dp[n][1][S2]) - dis[n][1]);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值