题目链接:点击打开链接
比赛的时候没看出来树有什么用,于是就变成了想尽办法去解决这个x着色问题。
然而这是个NPhard问题。。这种数据规模解决不了orz
赛后经菊苣提醒才知道这个树结构才是关键。。
因为每种冰淇淋所在的所有点在这颗树上是一个连通块,也就是说,沿着树搜索下去,不可能出现已经染过色且父亲中没有的冰淇淋重新出现的问题。
于是就可以直接贪心构造一波就行了。在这颗树中随便找一个点为根然后dfs下去,每次对其所拥有的冰淇淋进行染色,如果这种冰淇淋没有被染色就尽量染已经出现过的颜色就行了。
代码如下:
#include <bits/stdc++.h>
using namespace std;
struct node
{
vector<int> v;
};
node a[300005];
vector<int> e[300005];
map<int,int> mp;
bool vis[300005];
int n,m;
set<int> st;
void dfs(int pos)
{
st.clear();
for(int i=0;i<a[pos].v.size();i++)
{
if(mp.find(a[pos].v[i])!=mp.end())
st.insert(mp[a[pos].v[i]]);
}
int cnt=1;
for(int i=0;i<a[pos].v.size();i++)
{
if(mp.find(a[pos].v[i])==mp.end())
{
while(st.find(cnt)!=st.end())cnt++;
mp[a[pos].v[i]]=cnt;
st.insert(cnt);
}
}
vis[pos]=true;
for(int i=0;i<e[pos].size();i++)
if(!vis[e[pos][i]])dfs(e[pos][i]);
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
mp.clear();
memset(vis,0,sizeof(vis));
for(int i=1;i<n;i++)
{
e[i].clear();
a[i].v.clear();
}
for(int i=1;i<=n;i++)
{
int k;
scanf("%d",&k);
for(int j=0;j<k;j++)
{
int p;
scanf("%d",&p);
a[i].v.push_back(p);
}
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1);
int mx=0;
for(int i=1;i<=m;i++)
if(mp.find(i)==mp.end())
mp[i]=1;
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
mx=max(mx,(*it).second);
printf("%d\n",mx);
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
{
if(it!=mp.begin())printf(" ");
printf("%d",(*it).second);
}
printf("\n");
}
return 0;
}