题意:输入一个n (3≤n≤9999) 个点m条边 (2≤m≤100000) 的连通图,n保证为奇数。设k为最小的奇数,使得每个点的度数不超过k,你的任务是把图中的结点涂上颜色1~k,使得相邻结点的颜色不同。多解时输出任意解。输入保证有解。(本段摘自《算法竞赛入门经典(第2版)》)
分析:
对于n为奇数的情况,每个结点的度数最多为
n−1
,为偶数,则k为n为奇数,对于n这个结点和与之相邻的
n−1
个结点一定存在一种染色方案,因此直接BFS进行染色即可。
代码:
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <set>
#include <string>
using namespace std;
const int maxn = 10005;
struct Edge
{
int from, to, dist;
Edge(int f, int t, int d) : from(f), to(t), dist(d) {}
};
struct Map
{
int n, m, k;
vector< Edge > edges;
vector< int > G[maxn];
int color[maxn];
int v[maxn];
int vc[maxn];
int q[maxn];
void init(int n)
{
this->n = n;
for (int i = 0; i < n; ++i)
G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int dist)
{
edges.push_back(Edge(from, to, dist));
m = edges.size();
G[from].push_back(m - 1);
}
void find_k()
{
k = 0;
for (int i = 0; i < n; ++i)
k = max(k, (int)G[i].size());
if (!(k & 1))
++k;
printf("%d\n", k);
}
void BFS()
{
memset(color, -1, sizeof(color));
memset(v, 0, sizeof(v));
int head = 0, tail = 0;
q[tail++] = 0;
v[0] = 1;
while (head != tail)
{
memset(vc, 0, sizeof(vc));
for (int i = 0; i < G[q[head]].size(); ++i)
{
Edge& e = edges[G[q[head]][i]];
if (!v[e.to])
{
q[tail++] = e.to;
v[e.to] = 1;
}
else if (color[e.to] != -1)
vc[color[e.to]] = 1;
}
for (int i = 1; i <= k; ++i)
if (!vc[i])
{
color[q[head]] = i;
break;
}
++head;
}
for (int i = 0; i < n; ++i)
printf("%d\n", color[i]);
}
};
Map M;
int n, m, x, y;
bool first;
int main()
{
while (~scanf("%d%d", &n, &m))
{
if (first)
printf("\n");
else
first = true;
M.init(n);
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &x, &y);
M.AddEdge(x - 1, y - 1, 1);
M.AddEdge(y - 1, x - 1, 1);
}
M.find_k();
M.BFS();
}
return 0;
}