[SDOI2019] 热闹的聚会与尴尬的聚会
problem
luogu-P5361
他的聯系薄上有 nnn 位好友,他們兩兩之間或者互相認識,或者互相不認識。
小 Q 希望在周六辦一個熱鬧的聚會,再在周日辦一個尷尬的聚會。
- 一場熱鬧度為 ppp 的聚會請來了任意多位好友,對于每一位到場的好友來說都有至少 ppp 位他認識的好友也參加了聚會,且至少對于一位到場的好友來說現場恰好有 ppp 位他認識的好友;
- 一場尷尬度為 qqq 的聚會請來了恰好 qqq 位好友,且他們兩兩互不認識。
兩場聚會可能有重復的參與者,聯系薄上也有可能有某些好友同時缺席了兩場聚會。
小 Q 喜歡周六聚會的熱鬧度 ppp 與周日聚會的尷尬度 qqq 之間滿足:?np+1?≤q\left\lfloor \frac{n}{p+1} \right\rfloor\le q?p+1n??≤q 且 ?nq+1?≤p\left\lfloor \frac{n}{q+1} \right\rfloor \le p?q+1n??≤p。
請幫助小 Q 找出一個可行的邀請方案。
solution
observation1:\text{observation1}:observation1: ?np+1?≤q∧?nq+1?≤p?(p+1)(q+1)≥n+1\lfloor\frac{n}{p+1}\rfloor\le q\wedge \lfloor\frac{n}{q+1}\rfloor\le p\Leftrightarrow (p+1)(q+1)\ge n+1?p+1n??≤q∧?q+1n??≤p?(p+1)(q+1)≥n+1。
我們只需要分別最大化 p,qp,qp,q 即可。
看似是兩個獨立的部分,實際上他們各自的構造方式是一樣的原理。
- 熱鬧的聚會。即度數限制的圖。
每次找出當前圖中度數最小的點,更新 ppp 的最大值。
并刪掉這個點,動態地改變與之相連的其余點的度數。
將彈出的編號桉順序記錄下來,并記下最大值的位置。
位置以前的點則是不被選的。
-
尷尬的聚會。即獨立集。
每次找出當前圖中度數最小的且未被標記的點,加入尷尬的聚會。
然后標記與之直接相連的所有點都不能參加聚會。
下面給出該構造的正確性證明:
將每個點加入尷尬的聚會,除去這個點本身,最多會從圖中刪掉 ppp 個點。顯然 q≥?np+1?q\ge \lceil\frac{n}{p+1}\rceilq≥?p+1n??。
如果獨立集的選點運行了 qqq 次,第 iii 次刪掉的點度數為 did_idi?。
則有 ∑i=1q(di+1)≥n\sum_{i=1}^q(d_i+1)\ge n∑i=1q?(di?+1)≥n。而 (q+1)?max?(di+1)≥n(q+1)·\max(d_i+1)\ge n(q+1)?max(di?+1)≥n 顯然。
code
#include <bits/stdc++.h> using namespace std; #define maxn 10005 #define Pair pair < int, int > int T, n, m; int p[maxn], q[maxn], vis[maxn], deg[maxn], d[maxn]; vector < int > G[maxn]; priority_queue < Pair, vector < Pair >, greater < Pair > > Q;int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) deg[i] = 0;for( int i = 1;i <= n;i ++ ) G[i].clear();for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );deg[u] ++, deg[v] ++;}int ans1 = 0, cnt1 = 0, pos;for( int i = 1;i <= n;i ++ ) vis[i] = 0;for( int i = 1;i <= n;i ++ ) d[i] = deg[i];for( int i = 1;i <= n;i ++ ) Q.push( make_pair( d[i], i ) );while( ! Q.empty() ) {int u = Q.top().second, w = Q.top().first; Q.pop();if( vis[u] ) continue; vis[u] = 1;p[++ cnt1] = u;if( w > ans1 ) ans1 = w, pos = cnt1;for( int v : G[u] ) if( ! vis[v] ) Q.push( make_pair( --d[v], v ) );}int ans2 = 0, cnt2 = 0;for( int i = 1;i <= n;i ++ ) vis[i] = 0;for( int i = 1;i <= n;i ++ ) d[i] = deg[i];for( int i = 1;i <= n;i ++ ) Q.push( make_pair( d[i], i ) );while( ! Q.empty() ) {int u = Q.top().second, w = Q.top().first; Q.pop();if( vis[u] ) continue;vis[u] = 1;q[++ cnt2] = u;for( int v : G[u] ) vis[v] = 1;}for( int i = 1;i <= n;i ++ ) vis[i] = 0;for( int i = 1;i <= pos;i ++ ) vis[p[i]] = 1;printf( "%d ", n - pos );for( int i = 1;i <= n;i ++ ) if( ! vis[i] ) printf( "%d ", i );puts("");printf( "%d ", cnt2 );for( int i = 1;i <= cnt2;i ++ ) printf( "%d ", q[i] );puts("");}return 0; }總結
以上是生活随笔為你收集整理的[SDOI2019] 热闹的聚会与尴尬的聚会的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 家里的无线网络密码怎么改家里wifi怎样
- 下一篇: [CQOI2018] 解锁屏幕(状压dp