您的位置:首页 > 其它

Bad Horse - Practice Round China New Grad Test 2014 - BFS - 二分图判定

2014-03-09 21:19 483 查看
Bad Horse

题意:判断某图(不一定是简单图)是否为二分图。 难度:3星。

一开始做的时候没有意识到这是二分图的问题,考虑不周全,做错了。想的是:任意两个点(怪)的连接集(矛盾集)之间没有交集,则可推断出肯定结果。这并不是判定二分图的充分条件。

后来搜索发现,应该用广度优先搜索算法(BFS)来判定题图是否二分图。果然去年学的数据结构记不清了,得再温习一下BFS。其他的知识想必也需要温习了!

思路:用广度优先遍历每个节点,为其着色。若碰到相邻节点间的颜色相同,则说明题图非二分图。需要注意题图为非连通图的情况,须在BFS外套一个循环。

题解代码:

/*
*	Bad Horse - Practice Round China New Grad Test 2014
*
*
*	原错误思路:任意两个点(怪)的连接集(矛盾集)之间没有交集,
*		则可以分为两个没有内部连接的子集;——(这不就是偶图嘛)
*	题目应等价为:判断某图是否二分图;
*
*	用广度优先搜索算法(BFS)解决:
*	1、建立邻接表:
*		从文件读取数据,建立nameList[][]、邻接表troubleNo[][];
*	2、根据邻接表用广度优先搜索算法为每个节点着色:
*		1)初始化,将节点0(nameList[0][])着色为‘1’(即,color[0]=1);
*		2)建立一个先进先出的队列queue[],将节点0加入队列;
3)取出头节点(节点0),将其相邻节点加入队列,并将相邻节点着异色(即,color[i]=1-color[0]);
*			如果邻节点已着色,且与现节点的颜色相同,则说明题图非二分图,break;
*		4)循环取出队列头节点,用类似3)的方法处理,直至处理完此连通图中全部节点;
*	3、为处理题图为非连通图(由多个简单图组成)的情况,须在外层再套一个循环;
*
*/

#include <iostream>
#include <fstream>

using namespace std;

#define MAX_NAME_LENGTH 32
#define MAX_NAME_NUMBER 200

int makeNameList(char name[]);

char nameList[MAX_NAME_NUMBER][MAX_NAME_LENGTH];
int troubleNo[MAX_NAME_NUMBER][MAX_NAME_NUMBER], nameCnt;
int color[MAX_NAME_NUMBER];
int queue[MAX_NAME_NUMBER], head, tail;

int main()
{
ifstream inputFile;
ofstream outputFile;
int T, M;
char nameA[MAX_NAME_LENGTH], nameB[MAX_NAME_LENGTH];
int nameANo, nameBNo;
int canSplit;
int i, j, caseNo;

inputFile.open("E:\\C++\\GCJ\\China New Grad Test 2014\\Practice Round\\Bad Horse\\A-small-practice-2.in");
outputFile.open("E:\\C++\\GCJ\\China New Grad Test 2014\\Practice Round\\Bad Horse\\A-small-practice-2.out");

inputFile >> T;

for (caseNo = 1; caseNo <= T; caseNo++)
{
inputFile >> M;
for (i = 0; i < 2 * M; i++)
{	/* troubleNo[i][0]存储的是与nameList[i][]邻接的节点个数 */
troubleNo[i][0] = 0;
}

for (i = 0, nameCnt = 0; i < M; i++)
{
inputFile >> nameA >> nameB;
cout << nameA << ' ' << nameB << endl;

/* 输入nameA、nameB,返回值为各自序号 */
nameANo = makeNameList(nameA);
nameBNo = makeNameList(nameB);
/* 建立邻接表 */
troubleNo[nameANo][++troubleNo[nameANo][0]] = nameBNo;
troubleNo[nameBNo][++troubleNo[nameBNo][0]] = nameANo;
}//for (i = 0, nameCnt = 0; i < M; i++)

canSplit = 1;
memset(color, 0, sizeof(int) * MAX_NAME_NUMBER);
while (1)
{	/* BFS */
/* 找到未访问的节点(color[j]==0) */
for (j = 0; color[j] && j < nameCnt; j++);
if (j == nameCnt)
{
break;
}

head = tail = 0;
queue[tail++] = j;
color[j] = 1;
while (head < tail)
{	/* 队列不为空 */
int tmp = queue[head++];	/* 取出头节点 */
for (j = 1; j <= troubleNo[tmp][0]; j++)
{	/* troubleNo[j][0]存储的是与nameList[j][]邻接的节点个数 */
if (!color[troubleNo[tmp][j]])
{	/* 若邻接点未着色,将其着与现节点不同的颜色,并将其加入队列 */
queue[tail++] = troubleNo[tmp][j];
color[troubleNo[tmp][j]] = 0 - color[tmp];
}
else if (color[troubleNo[tmp][j]] == color[tmp])
{	/* 若邻接点与现节点颜色相同,说明原图非二分图,break */
canSplit = 0;
goto nextCase;
}
}//for (j = 1; j <= troubleNo[tmp][troubleNo[tmp][0]]; j++)
}//while (head < tail)
}//while (1)

nextCase:
if (!canSplit)
{
cout << caseNo << " No\n";
outputFile << "Case #" << caseNo << ": No\n";
}
else
{
cout << caseNo << " Yes\n";
outputFile << "Case #" << caseNo << ": Yes\n";
}
}//for (caseNo = 1; caseNo <= T; caseNo++)

inputFile.close();
outputFile.close();

system("pause");
return 0;
}

int makeNameList(char name[])
{	/* 输入name */
/* 返回name的序号 */
int i, existFlag;
for (i = 0, existFlag = 0; i < nameCnt; i++)
{
if (!strcmp(nameList[i], name))
{
existFlag = 1;
break;
}
}
if (!existFlag)
{
strcpy(nameList[nameCnt++], name);
}

return i;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  GCJ 二分图 BFS