2018百度之星初賽(B)degree

degree

http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=826&pid=1001

Accepts: 1581

Submissions: 3494

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 131072/131072 K (Java/Others)

Problem Description

度度熊最近似乎在研究圖論。給定一個有 N 個點 (vertex) 以及 M 條邊 (edge) 的無向簡單圖 (undirected simple graph),此圖中保證沒有任何圈 (cycle) 存在。 現在你可以對此圖依序進行以下的操作: 1. 移除至多 K 條邊。 2. 在保持此圖是沒有圈的無向簡單圖的條件下,自由的添加邊至此圖中。 請問最後此圖中度數 (degree) 最大的點的度數可以多大呢?

Input

輸入的第一行有一個正整數 T ,代表接下來有幾筆測試資料。 對於每筆測試資料:第一行有三個整數 N , M , K 。接下來的 M 行每行有兩個整數 a 及 b ,代表點 a 及 b 之間有一條邊。點的編號由 0 開始至 N−1 。 * 0≤K≤M≤2×105 * 1≤N≤2×105 * 0≤a,b<N * 給定的圖保證是沒有圈的簡單圖 * 1≤T≤23 * 至多 2 筆測試資料中的 N>1000

Output

對於每一筆測試資料,請依序各自在一行內輸出一個整數,代表按照規定操作後可能出現的最大度數。

Sample Input

Copy

2
3 1 1
1 2
8 6 0
1 2
3 1
5 6
4 1
6 4
7 0

Sample Output

Copy

2
4

題解:

沒有圈 (cycle) 的簡單圖 (undirected simple graph),等價於由多顆樹 (tree) 組成的森林 (forest)。這裏用 V 代表點的數量,E 代表邊的數量 (取代題目中的 N 以及 M),C 代表森林中樹的數量。 

## K=0 的 case 不妨先化簡一下題目,在 K=0 的狀態下要達到 degree 最大化,可以貪心的把森林中所有樹各自接一條邊到已知 degree 最大的點上。答案是 C + 已知最大的 degree - 1。 

## K≥0 的 case 回到原題,題目中規定一定要在添加邊之前把拔邊的操作作完,但是實際上任意調換添加邊以及拔掉邊的順序不會影響最後的結果。考慮貪心添加完邊的樹,可以多拔掉一條邊再重新接上的效果等同於把答案 +1,要注意的是如果答案已經到達最大值 V-1 的話,那拔邊再接上並不會影響答案。所以答案為min(V - 1, K + C + 已知最大的 degree - 1)。 

## 樹的數量 C = V - E 由於給定的圖是面數 (face) 爲 1 的平面圖 (planar graph),所以根據平面圖的公式 V-E+F=C+1 整理後 C=V-E。另外一個證明:圖中每個 connected component 都是由樹所組成,也就是說每個 component 中邊數會是點數 - 1,直接可推得 C=V?E。 有了 C=V-E 後,答案就變成 min(V - 1, K + V - E + 已知最大的 degree - 1)。也就是,我們其實不用真正的寫出計算 connected component 的算法,只要統計 degree 最大的點有多大就可以計算出答案了。 整個時間複雜度爲 O(V),注意這題中有 O(V)=O(E)。

代碼:

#include<iostream>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;

int s[200005];

int main()
{
    int t;
    int n,m,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(s,0,sizeof(s));
        int a,b;
        for(int i=0;i<m;i++)
        {
            cin>>a>>b;
            s[a]++;
            s[b]++;
        }
        int maxx=0;
        for(int i=0;i<n;i++)
        {
            if(maxx<s[i])
                maxx=s[i];
        }
        //cout<<"    "<<maxx<<endl;
        int c=n-m;  //樹的數量
        if(k==0)
            cout<<c+maxx-1<<endl;
        else
            cout<<min(n-1,k+c+maxx-1)<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章