codeforces 1037E (圖論好題)
阿新 • • 發佈:2018-12-16
演算法:思維!
難度:NOIP+
簡述題意:
給一幅圖,邊從0開始每天多一條邊,問每天增加邊之後能夠有多少人去旅遊。
能去旅遊的定義是隻有當聯通的點的度數都大於等於k才能去旅遊,否則都不能去旅遊。
題解:
首先,我們將題目抽象為一張無向圖,問題轉化為動態加邊(不好寫)(之前寫的一道並查集的題,也是要倒序列舉刪邊!可以去翻我的部落格),在某一時刻最多能選多少個點,s.t.被選的點中任意一點都與其他被選的點有至少k條連邊。 正向不太好做,我們可以逆向考慮(正難則反): 首先把所有的邊都加進來。顯然此時度數還小於k的點是永遠不可能對答案有貢獻了,因此要刪去,同時更新一下與它相鄰的點的度數。重複以上操作,直到所有點的度數都大於等於k。此時剩餘點的數量就是第m天時的答案。然後我們倒著列舉,每次刪邊,並重覆上述操作,然後記錄一下這一天的答案。最後注意一下正序輸出就AC啦!
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <set> #include <vector> #include <queue> #define ll long long #define N 200005 using namespace std; set<int>S[N]; int cnt; int deg[N],ans[N],del[N]; struct node { int fr; int to; }edg[N]; int n,m,k; void dele(int u) { if(del[u]||deg[u]>=k) return ; queue<int>q; q.push(u); del[u]=1; --cnt; while(!q.empty()) { int x=q.front(); q.pop(); for(auto v : S[x])//C++11 吃多了! 再也不用寫迭代器了 { --deg[v]; if(deg[v] < k && !del[v]) { q.push(v); del[v]=1; --cnt; } } } } int main() { scanf("%d%d%d",&n,&m,&k); cnt=n; for(int i = 1;i <= m;i++) { int a,b; scanf("%d%d",&a,&b); edg[i].fr=a,edg[i].to=b; deg[a]++,deg[b]++; S[a].insert(b),S[b].insert(a); } for(int i = 1;i <= n;i++) { dele(i); } ans[m]=cnt; for(int i = m; i >= 1; --i) { if(!del[edg[i].fr]) --deg[edg[i].to]; if(!del[edg[i].to]) --deg[edg[i].fr]; S[edg[i].fr].erase(edg[i].to), S[edg[i].to].erase(edg[i].fr); dele(edg[i].fr), dele(edg[i].to); ans[i-1] = cnt; } for(int i = 1;i <= m;i++) { printf("%d\n",ans[i]); } return 0 ; }
C++11知識點:
1、auto!!!(百度去吧) 可以不用寫迭代器啦,哈哈哈
2、unordered_map