Problem
As the leader of the Evil League of Evil, Bad Horse has a lot of problems to deal with. Most recently, there have been far too many arguments and far too much backstabbing in the League, so much so that Bad Horse has decided to split the league into two departments in order to separate troublesome members. Being the Thoroughbred of Sin, Bad Horse isn’t about to spend his valuable time figuring out how to split the League members by himself. That what he’s got you – his loyal henchman – for.
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a positive integer M on a line by itself – the number of troublesome pairs of League members. The next M lines each contain a pair of names, separated by a single space.
Output
For each test case, output one line containing “Case #x: y”, where x is the case number (starting from 1) and y is either “Yes” or “No”, depending on whether the League members mentioned in the input can be split into two groups with neither of the groups containing a troublesome pair.
Limits
1 ≤ T ≤ 100.
Each member name will consist of only letters and the underscore character.
Names are case-sensitive.
No pair will appear more than once in the same test case.
Each pair will contain two distinct League members.
Small dataset
1 ≤ M ≤ 10.
Large dataset
1 ≤ M ≤ 100.
solution
该题为经典的二分图问题,二分图的定义是:
设 G=(V,E) 是一个无向图。如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。则称图G为二分图。也就是说在二分图中,顶点可以分为两个集合X和Y,每一条边的两个顶点都分别位于X和Y集合中。
求二分图的最大匹配有很多经典的解法比如最大流,匈牙利算法等。这里我们只需要判定一个图是否为二分图,可以借鉴图着色的想法,每条边的两个端点颜色不同。比如我们可以选择一个图的端点A,将其染色为red,随后将A所有的相邻节点染色为blue,广度遍历下去当一个节点原本的颜色与要染的颜色不同时,则发生冲突,该图不是二分图。
算法过程为:借助队列,进行宽度优先遍历,先对一个起点着色RED,然后将其所有相邻的节点着色为BLUE,并加入队列。只要能保证相邻的节点是不同的颜色即可。
需要注意的是要注意多个非联通子图的情况
源代码
#include<iostream>
#include<string>
#include<map>
#include<queue>
using namespace std;
int main(void)
{
freopen("test.in", "r", stdin);
freopen("result.out", "w", stdout);
int n;
cin >> n;
int count = 1;
for (; count <= n; count++)
{
int T;
cin >> T;
string a, b;
map<string, int> hashmap;//string对int的对应表
//最多两倍空间
int **graph = new int*[2*T];
int *vertex = new int[2 * T];//保存vertex的颜色,0为初始颜色
for (int i = 0; i < 2 * T; i++)
{
graph[i] = new int[2 * T];
vertex[i] = 0;//初始化端点的颜色,0代表未着色
}
int tag = 0;
for (int i = 0; i < T; i++)
{
cin >> a >> b;
if (hashmap.find(a) == hashmap.end())//第一次插入
hashmap[a] = tag++;
if (hashmap.find(b) == hashmap.end())//第一次插入
hashmap[b] = tag++;
graph[hashmap[a]][hashmap[b]] = 1;//邻接矩阵有联系置为1
graph[hashmap[b]][hashmap[a]] = 1;
}
queue<int> myQueue;
int allflag = 1;
int flag = 1;
while (allflag)
{
flag = 1;
int j;
//是否所有元素都已经着色,处理多个非联通子图
for (j = 0; j < tag; j++)
if (vertex[j] == 0)
break;
if (j == tag)
allflag = 0;
else
{
vertex[j] = 1;
myQueue.push(j);
while (!myQueue.empty())//not empty
{
int cur = myQueue.front();
myQueue.pop();
int cor;
for (int i = 0; i < tag; i++)
{
if (graph[cur][i]== 1)//子节点
{
cor = 0 - vertex[cur];//与父节点颜色不同用1和-1表示
if (vertex[i] == 0)//只有未标记过的结点才放入队列中
{
vertex[i] = cor;
myQueue.push(i);
}
else if (vertex[i] != 0 && vertex[i] != cor)//conflict
{
flag = 0;
break;
}
}
}
if (flag == 0)
break;
}
}
if (flag == 0)
break;
}
if (flag == 0)
cout << "Case #" << count << ": No\n";
else if (flag ==1)
cout << "Case #" << count << ": Yes\n";
hashmap.clear();
for (int i = 0; i < 2 * T; i++)
delete[]graph[i];
delete[] graph;
delete[] vertex;
}
}