hdu1689 Alien’s Necklace--BFS & 奇偶标记

原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=1689


一:题意

组成手串,给N个珠子,珠子之间有M对关系,有关系的可以相邻,开头与末尾算相邻,能否求出一个手串长度满足:

长度最短;

长度最小为3;

长度是奇数;


二:分析

以每一个珠子为起点,开始bfs,比较难理解的是vis标记数组,它的二维表示的是奇偶。

例如:vis[ k ][ 0 ]表示在当前路线,以k结尾的长度是偶数;若是vis[ k ][ 1 ],长度就是奇数。

看别人的解题报告时,还是有些疑问的,这里记录下。

一共有四种情况:

1:在一条路线上遇见两个k值,且节点处的奇偶相同

这种情况已经被vis标记,直接结束了,不用讨论了。

2.在一条路线上遇见两个k值,且奇偶不同

奇偶不同,代表第二次出现的k还是要被加入到队列,因为vis并没有标记,但是按常理来说,珠子只能用一次,在这里应该及时停止入队的啊,这是算法的小缺陷,大家可以想一下,两个相同k之间的节点还是会走一遍,到时又遇到第三个k,停止,浪费了很多资源

3.在两条线各遇见一个k值,且节点数奇偶一样

k一样,奇偶一样,vis标记,第二次遇见k的这个节点被放弃,不入队,但是这样是否正确,是正确的。因为第二次遇见k时,整个路线长度才刚刚和第一次遇见k的路线长度相等,这是为何,我在前面的博客介绍过,就是队列的step值极大差最大只能是1。

4.在两条线各遇见一个k值,奇偶不同

这就不用说了,各不影响,主要是上面的三种情况。


三:AC代码

#define _CRT_SECURE_NO_DEPRECATE 

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

#define N 1005
const int inf = 0x7fffffff;

vector<int>g[N];
int vis[N][2];

struct node
{
	int u, t;//t是珠子数
};

int bfs(int s)
{
	int i, u, v;
	queue<node >q;
	node cur, next;
	cur.u = s;
	cur.t = 1;
	memset(vis, 0, sizeof(vis));
	vis[s][1] = 1;       //奇数点,用一个珠子
	q.push(cur);
	while (!q.empty())
	{
		cur = q.front();
		q.pop();
		u = cur.u;
		for (i = 0; i < g[u].size(); i++)
		{
			next.u = v = g[u][i];
			next.t = cur.t + 1;
			if (v == s&&next.t % 2 == 0 && next.t > 3)   //结点处到达两次,故应该减一
				return next.t - 1;
			if (!vis[v][next.t % 2])
			{
				vis[v][next.t % 2] = 1;
				q.push(next);
			}
		}
	}
	return inf;
}

int main()
{
	int i, n, m, u, v, tt, cnt = 0;
	scanf("%d", &tt);
	while (tt--)
	{
		scanf("%d%d", &n, &m);
		for (i = 1; i <= n; i++)
			g[i].clear();
		while (m--)
		{
			scanf("%d%d", &u, &v);
			g[u].push_back(v);
			g[v].push_back(u);
		}
		int ans = inf;
		for (i = 1; i <= n; i++)
			ans = min(ans, bfs(i));
		if (ans == inf)
			printf("Case %d: Poor JYY.\n", ++cnt);
		else
			printf("Case %d: JYY has to use %d balls.\n", ++cnt, ans);
	}
	return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值