Three Kingdoms(BFS+优先队列)

http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=103#problem/J

题意:

给一张 n*m 的地图,上面有一些带有攻击性的塔

A 攻击范围是 2,伤害值是 1

B 攻击范围是 3,伤害值是 2

C 凡是踏入这个点的都要受到 3 的伤害

D 攻击范围是 2,伤害值是 4

E 攻击范围是 1,伤害值是 5

$ 代表刘备

! 代表终点

. 代表空地

# 代表墙

刘备不能走到 A,B,D,E ,但是可以走到 . 和 C

刘备不会被同样的塔伤害两次.

问到达目的地需要的最少HP


思路:开始定义每个节点增加一个vis[],标记到达该点时已经被哪些塔伤害过。但是BFS是一个动态的搜索,搜索到这个点时就会把原来的vis[]覆盖掉,200+行的代码。。。

正确的思路应该是对访问数组增加一维,mark[n][m][32],可以想象成对每个点多增加了一个限制,即该点受到塔伤害的情况。共有ABCDE五种塔,那么共有32中伤害情况。当BFS到某一点时,先根据前一个点判断它是否受到某种塔的攻击,如果没受到过,那么就会被攻击并标记在这以状态时已经被攻击。


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;

char map[55][55];
int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };

struct node
{
	int x,y;
	int hurt;
	int sta;
	bool operator < (const struct node &tmp)const
	{
		return hurt > tmp.hurt;
	}
}p[2560];
int n,m;
int sx,sy,ex,ey;
int mark[55][55][33];
int hurt[55][55][6];

void init()
{
	memset(hurt,0,sizeof(hurt));
	int i,j,k,g;

	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= m; j++)
		{
			if(map[i][j] == 'A')
			{
				for(k = i-2; k <= i+2; k++)
				{
					for(g = j-2; g <= j+2; g++)
					{
						if(k >= 1 && k <= n && g >= 1 && g <= m && abs(k-i)+abs(g-j) == 2)
							hurt[k][g][0] = 1;
					}
				}
			}

			else if(map[i][j] == 'B')
			{
				for(k = i-3; k <= i+3; k++)
				{
					for(g = j-3; g <= j+3; g++)
					{
						if(k >= 1 && k <= n && g >= 1 && g <= m && abs(k-i)+abs(g-j) == 3)
							hurt[k][g][1] = 2;
					}
				}
			}

			else if(map[i][j] == 'C')
			{
				hurt[i][j][2] = 3;
			}

			else if(map[i][j] == 'D')
			{
				for(k = i-2; k <= i+2; k++)
				{
					for(g = j-2; g <= j+2; g++)
					{
						if(k >= 1 && k <= n && g >= 1 && g <= m && abs(k-i)+abs(g-j) == 2)
							hurt[k][g][3] = 4;
					}
				}
			}

			else if(map[i][j] == 'E')
			{
				for(k = i-1; k <= i+1; k++)
				{
					for(g = j-1; g <= j+1; g++)
					{
						if(k >= 1 && k <= n && g >= 1 && g <= m && abs(k-i)+abs(g-j) == 1)
							hurt[k][g][4] = 5;
					}
				}
			}
		}
	}
}

bool judge(int x, int y)
{
	if(map[x][y] == 'C' || map[x][y] == '!' || map[x][y] == '.' || map[x][y] == '$')
		return true;
	return false;
}

int bfs()
{
	priority_queue <struct node> que;
	while(!que.empty()) que.pop();
	struct node tmp;
	que.push( (struct node) {sx,sy,0,0} );
	mark[sx][sy][0] = 1;

	while(!que.empty())
	{
		struct node u = que.top();
		que.pop();
		if(u.x == ex && u.y == ey)
		{
			return u.hurt;
		}

		for(int d = 0; d <= 3; d++)
		{
			tmp.x = u.x + dir[d][0];
			tmp.y = u.y + dir[d][1];
			tmp.hurt = u.hurt;
			tmp.sta = u.sta;
			if(judge(tmp.x,tmp.y) && tmp.x >= 1 && tmp.x <= n && tmp.y >= 1 && tmp.y <= m)
			{
				for(int k = 0; k < 5; k++) //枚举五种塔,判断是否被该种塔攻击过
				{
					if( (tmp.sta & (1 << k)) == 0 && hurt[tmp.x][tmp.y][k])//若没被攻击过且在当前点时能够被周围的塔攻击
					{
						tmp.hurt += hurt[tmp.x][tmp.y][k];
						tmp.sta += (1 << k); //标记已被攻击过
					}
				}

				if( !mark[tmp.x][tmp.y][tmp.sta] )//没有访问过进队列
				{
					mark[tmp.x][tmp.y][tmp.sta] = 1;
					que.push(tmp);
				}
			}
		}
	}
	return -1;
}

int main()
{
	int test;
	scanf("%d",&test);

	for(int item = 1; item <= test; item++)
	{
		scanf("%d %d",&n,&m);

		for(int i = 1; i <= n; i++)
		{
			scanf("%s",map[i]+1);
			for(int j = 1; j <= m; j++)
			{
				if(map[i][j] == '$')
				{
					sx = i;
					sy = j;
				}
				if(map[i][j] == '!')
				{
					ex = i;
					ey = j;
				}
			}
		}

		init(); //预处理每一点的受到的攻击。
		memset(mark,0,sizeof(mark));
		int ans = bfs();
		printf("Case %d: %d\n",item,ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个任务可以分为以下几部分: 1. 读取文件并提取人名 2. 对人名进行计数 3. 生成词频最高的10-20个词 4. 生成词云 我们可以使用Python中的一些第三方库来实现这些功能。具体实现如下: ```python # 导入所需的库 import jieba from collections import Counter from wordcloud import WordCloud import matplotlib.pyplot as plt # 读取文件 with open('Romance of the Three Kingdoms.txt', 'r', encoding='utf8') as f: text = f.read() # 提取人名 words = jieba.cut(text) names = [] for word in words: if len(word) > 1 and word[0] == '第': # 排除章节名 continue names.append(word) # 计数 name_cnt = Counter(names) name_cnt = dict(name_cnt.most_common()) # 生成词频最高的10-20个词 top_names = list(name_cnt.keys())[:20] # 生成词云 wc = WordCloud(font_path='msyh.ttc', background_color='white', max_words=2000, width=800, height=600) wc.generate_from_frequencies(name_cnt) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() ``` 解释一下代码: 1. 使用jieba库进行中文分词,提取人名。 2. 对人名进行计数,并使用字典的方式保存结果。 3. 取出前20个最高频的人名,作为词云的输入。 4. 使用WordCloud库生成词云,并使用matplotlib库显示结果。 需要注意的是,这个版本的代码没有去重,所以结果中可能会出现同一个人名出现多次的情况。如果需要更准确的处理方式,可以使用同义词词典进行替换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值