GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版
一道简单题,但我一开始想复杂了。
我一开始想的是,要求最优解,用dfs遍历,每经过一个节点时,尝试所有可能的颜色,如果遇到冲突的地方,即颜色用完了,就回溯回来尝试下一个颜色。但这样时间复杂度很高,根本不可能昨晚。
我又看这一章节的算法:贪心。那就意味着不需要考虑"不合适"的情况。事实上,我们只需要遇到一个节点,就给这个节点赋值一个目前和他的直接节点无冲突的颜色即可。最后不会超过k的。
而且部分场景下,实际颜色值是小于度的,但是还需要按照k值要求输出。
AC代码
cpp
#include <stdio.h>
#include <string.h>
#include <list>
#define MAXN 10005
using namespace std;
int n, m;
list<int> edgeArr[MAXN];
int colorArr[MAXN];
int colorUse[MAXN];
// 获取度,注意实际染色的值可能小于度,但是这里还是要按照题目要求输出度的值或+1
int getK()
{
int i;
int k = 0;
for (i = 1; i <= n; ++i)
{
if (k < edgeArr[i].size())
k = edgeArr[i].size();
}
if (k % 2 == 0)
++k;
return k;
}
void init()
{
int i;
for (i = 0; i < MAXN; ++i)
{
edgeArr[i].clear();
colorArr[i] = 0;
}
}
// 只需要看a的临近点中已经染色的点,选一个没有重复的点即可,未染色的点无需考虑
void setNode(int a)
{
memset(colorUse, 0, sizeof(colorUse));
for (auto ip = edgeArr[a].begin(); ip != edgeArr[a].end(); ++ip)
{
if (colorArr[*ip])
colorUse[colorArr[*ip]] = 1;
}
for (int i = 1; i <= n; ++i)
{
if (!colorUse[i])
{
colorArr[a] = i;
return;
}
}
}
void dfs(int a)
{
if (colorArr[a])
return;
setNode(a);
for (auto ip = edgeArr[a].begin(); ip != edgeArr[a].end(); ++ip)
{
dfs(*ip);
}
}
int main()
{
int i;
int a, b;
while (scanf("%d %d", &n, &m) > 0 && n > 0)
{
init();
for (i = 0; i < m; ++i)
{
scanf("%d %d", &a, &b);
edgeArr[a].push_back(b);
edgeArr[b].push_back(a);
}
dfs(1);
printf("%d\n", getK());
for (i = 1; i <= n; ++i)
{
printf("%d\n", colorArr[i]);
}
printf("\n");
}
return 0;
}