[SPOJ UOFTCG Office Mates]
分类:dfs
tree
1. 题目链接
2. 题意描述
题意:
有N个学生,M 对朋友关系,学生只能挨着他的朋友坐。
桌子排列成一条直线,可以让一些桌子空出来,数据保证对于任何含K个学生的集合,最多只有K-1对朋友。
求最少需要多少张桌子。
数据:
(N<=100000)
输入第一行表示数据组数 T
对于每组测试数据,第一行为 N 和 M ,接下来 M 行表示 M 对朋友关系
输入文件不会超过2M
3. 解题思路
题意简单的描述就是最少链覆盖一个森林所有的顶点,求最少链数。(所有顶点只能使用一次)。那么显然答案就是顶点数+最少链数-1.
怎么求最少链数呢?
对于森林中的每一棵树,找到一个深度最大且儿子树目
≥2
的节点。将以这个节点为根节点的子树进行拆解。(这样就保证了这个节点是由若干条链组成的,而不是由子树)。
如果还不懂? 在纸上模拟一遍过程就很清楚啦。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 100000 + 7;
template <typename T>
inline bool scan_d (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template<typename T>
void print(T x) {
static char s[33], *s1; s1 = s;
if (!x) *s1++ = '0';
if (x < 0) putchar('-'), x = -x;
while(x) *s1++ = (x % 10 + '0'), x /= 10;
while(s1-- != s) putchar(*s1);
}
template<typename T> void println(T x) { print(x); putchar('\n');}
int T, n, m;
struct Edge {
int v, next;
} edge[MAXN << 1];
int head[MAXN], tot, fa[MAXN], du[MAXN], link[MAXN];
bool used[MAXN];
struct QNode {
int u, dep;
bool operator < (const QNode& e) const { return dep < e.dep; }
};
queue<QNode> Q;
void init() {
tot = 0;
memset(head, -1, sizeof(head));
memset(du, -1, sizeof(du));
memset(used, false, sizeof(used));
}
inline void add_edge(int u, int v) {
edge[tot] = Edge{v, head[u]};
head[u] = tot ++;
}
void dfs(int u, int pre, int k) {
fa[u] = pre;
du[u] = 0;
for(int i = head[u], v; ~i; i = edge[i].next) {
v = edge[i].v;
if(v == pre) continue;
++ du[u];
dfs(v, u, k + 1);
}
if(du[u] >= 2) Q.push(QNode{u, k});
}
void dfs2(int u) {
if(used[u]) return;
used[u] = true;
for(int i = head[u], v; ~i; i = edge[i].next) {
v = edge[i].v;
if(fa[u] == v) continue;
dfs2(v);
}
head[u] = -1;
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
int u, v;
scan_d(T);
while(T --) {
init();
scan_d(n), scan_d(m);
for(int i = 1; i <= m; ++i) {
scan_d(u), scan_d(v);
add_edge(u, v), add_edge(v, u);
}
for(int i = 1; i <= n; ++i) {
if(~du[i]) continue;
dfs(i, -1, 1);
}
int cnt = 0;
while(!Q.empty()) {
u = Q.front().u; Q.pop();
if(used[u] || du[u] < 2) continue;
cnt += du[u] - 1;
if(~fa[u]) -- du[fa[u]];
dfs2(u);
}
set<int> s;
for(int i = 1; i <= n; ++i) {
if(!used[i] && du[i] == 0) {
u = i;
while(~fa[u] && !used[fa[u]]) u = fa[u], used[u] = true;
s.insert(u);
}
}
cnt += s.size();
println(n + cnt - 1);
}
return 0;
}