HDU6228(2017acm-沈阳) 树/贪心
程序员文章站
2022-05-19 20:58:53
...
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6228
题目大意:
一棵树,k个颜色;
用这k颜色对这棵树染色;
设E(i)第i种颜色 所对应的节点 相连 构成的一棵树 的边的集合;
求Ei的交的最大值;
思路:
显然同种颜色要分布的越远越好;
虽然我们需要考虑的是边,但是我们可以转化为对每个节点去考虑; 令在这个节点的两侧每种颜色均有分布,那么一定会有一条公共边;
只算一条这样避免重复;
枚举每个节点i;
如果这个节点 左边的节点数和右边的节点数 都大于 k,那么这个点左右两边必有一条边在交集里面的;
网友们是怎么想到这个思路的,太nb了,蒟蒻瑟瑟发抖;
上码:
#include<cstdio>
#include<vector>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
int T,t,i,n,x,y,m,cnt;
vector<int> g[1000];
int dx[1000];
bool use[1000];
void DFS(int now)
{
dx[now]++;
use[now]=1;
for (int j=0; j<g[now].size(); j++)
{
int next=g[now][j];
if (use[next]==1) continue;
DFS(next);
dx[now]+=dx[next];
}
}
// 算出每个节点孩子的个数
void work(int now)
{
int s1=dx[now],s2=n-dx[now];
use[now]=1;
if (s1>=m && s2>=m) cnt++;
for (int j=0; j<g[now].size(); j++)
{
int next=g[now][j];
if (use[next]==1) continue;
work(next);
}
}
// 判断节点两边是否>=k
int main()
{
scanf("%d",&T);
for (t=1; t<=T; t++)
{
scanf("%d%d",&n,&m);
for (i=1; i<=n; i++) g[i].clear();
for (i=1; i<=n-1; i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
memset(use,0,sizeof(use));
memset(dx,0,sizeof(dx));
cnt=0;
DFS(1);
memset(use,0,sizeof(use));
work(1);
cout<<cnt<<endl;
}
}