HDU-6380
题目:
度度熊最近似乎在研究图论。给定一个有 NN 个点 (vertex) 以及 MM 条边 (edge) 的无向简单图 (undirected simple graph),此图中保证没有任何圈 (cycle) 存在。
现在你可以对此图依序进行以下的操作:
1. 移除至多 KK 条边。
2. 在保持此图是没有圈的无向简单图的条件下,自由的添加边至此图中。
请问最后此图中度数 (degree) 最大的点的度数可以多大呢?
Input
输入的第一行有一个正整数 TT,代表接下来有几笔测试资料。
对于每笔测试资料:
第一行有三个整数 NN, MM, KK。
接下来的 MM 行每行有两个整数 aa 及 bb,代表点 aa 及 bb 之间有一条边。
点的编号由 00 开始至 N−1N−1。
* 0≤K≤M≤2×1050≤K≤M≤2×105
* 1≤N≤2×1051≤N≤2×105
* 0≤a,b<N0≤a,b<N
* 给定的图保证是没有圈的简单图
* 1≤T≤231≤T≤23
* 至多 22 笔测试资料中的 N>1000N>1000
Output
对于每一笔测试资料,请依序各自在一行内输出一个整数,代表按照规定操作后可能出现的最大度数。
Sample Input
2 3 1 1 1 2 8 6 0 1 2 3 1 5 6 4 1 6 4 7 0
Sample Output
2 4
解题的话关键在于: 没有圈的简单图等价于由若干树组成的森林。
如果对图不熟的话也可以画一画,因为题目一直强调没有圈,从小到大选择顶点出发走一下也可以看出来。
如样例2:0和7组成一棵树,剩下的组成另一棵。
接下来进行题目的操作:删边、加边。然后找到最大度的点。
先看k = 0(没法删边),很明显,设图中最大度顶点为v,它所在的树treeV,总共有num棵树,那么只需将除treeV外的每一棵树都连一条边到顶点v,也就是treeV的根结点,此时v的度 = num - 1 + degree[v] 就是所求最大值。(degree[v]为v的度)
接下来看k>0,可以进行删边操作。既然说可以删边,那么就说明删边能够增大结点的度。
从k=0时,num - 1 + degree[v] 就是所求最大值可以看出,最大值与num有关,也就是说我们通过删边来增大树的棵树num,进而增加顶点v的度的最大值。
比方k = 1 时,任选一棵树,去掉这棵树的1条边,此时树变成两棵,删边完成了。num = num + 1 。加边的操作和k无关,把k看作0,就转化成第一种情况。
得到一般结论:
设num为初始图转化成森林时树的棵树,N为顶点数,M为边数,maxV为初始图中最大度顶点,ans为结果。
删边:num = num + k;
加边:ans = num - 1 + maxV;
随便找找规律或者简单证明下都可以得到:num = N - M;
最后,N个顶点度最大也只能是N-1。
//
// main.cpp
// 1001
//
// Created by jinyu on 2018/8/12.
// Copyright © 2018年 jinyu. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2*100000+7;
int degree[MAXN];
int N,M,K;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&N,&M,&K);
for(int i = 0;i<N+7;i++) degree[i] = 0;
int mm = M;
int ans = 0;
//int index = 0;
int maxV = 0;
while(mm--){
int f,t;
scanf("%d%d",&f,&t);
degree[f]++;
degree[t]++;
maxV = max( max(degree[f],degree[t]) , maxV);
}
int num = N - M + K;
ans = min( N-1 , maxV + num - 1);
printf("%d\n",ans);
}
return 0;
}