1. 程式人生 > >2018 ICPC 沈陽網絡預賽 Fantastic Graph (優先隊列)

2018 ICPC 沈陽網絡預賽 Fantastic Graph (優先隊列)

max print 找到 需要 ack 子圖 我們 span ret

【傳送門】https://nanti.jisuanke.com/t/31447

【題目大意】:有一個二分圖,問能不能找到它的一個子圖,使得這個子圖中所有點的度數在區間【L,R】之內。

技術分享圖片

【題解】首先我們分這幾種情況討論:

(1)如果集合U,V中存在某個點,它的度數小於L,那麽肯定就不滿足題意,直接輸出No。所以對任意i, degree[i] >= L

(2)如果集合U,V中所有點的度數都在給定區間內,直接輸出Yes。

(3)如果集合U,V中存在某些點的度數大於R,則需要減少與它關聯的邊,直到它的度數小於等於R

那麽如何刪邊呢?我們把某個度數過大的點X的所有終點放入優先隊列中,這個隊列根據點的度數排好序,度數大的點Y在隊首,當X的度數大於R時,我們取出隊首Y,如果Y度數大於L,代表可以刪邊,X,Y的度數均自減1。

如果X的度數大於R時,隊首Y的度已經不能再減(已經小於等於L了),那麽就表明找不到這樣的子圖,輸出No。

把所有的點都按照上述過程掃一遍,看中途是不是會判定找不到這樣的子圖。

時間復雜度:O(N*LogN)

有網上題解說可以使用網絡流,暫時記下以後再探討。

技術分享圖片

【AC代碼】

#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
using
namespace std; const int maxn = 41000; vector<int> G[maxn];//存圖 int offset = 20010;//兩個集合標號都從1開始為了區分設置一個偏移量,右邊的序號都加上偏移量 int degree[maxn];//存度數 // 自定義優先級 按度優先 struct cmp { bool operator()(const int &t1,const int &t2) { return degree[t1] < degree[t2]; } }; //初始化
void init(){ memset(degree , 0, sizeof degree); for(int i=0; i<maxn; i++) G[i].clear(); } int main(){ int n,m,k; int l,r; int u,v; int ca = 1; while(scanf("%d %d %d", &n,&m,&k) != EOF){ init(); int flag = 1; scanf("%d %d",&l, &r); //建圖,記錄度數 for(int i=1; i<=k; i++){ scanf("%d %d",&u, &v); G[u].push_back(v+offset); G[v+offset].push_back(u); degree[u]++; degree[v+offset]++; } //只要有一個點度數小於L就GG for(int i=1 ; i<=n; i++){ // cout<<" "<<degree[i]<<endl; if(degree[i] < l){ flag = 0; break; } } for(int i=1+offset; i<=m+offset; i++){ // cout<<" "<<degree[i]<<endl; if(degree[i] < l){ flag = 0; break; } } if(!flag){ printf("Case %d: No\n" , ca++); continue; } //開始執行步驟(3) 對左邊集合所有點 刪邊減度 for(int i=1; i<=n; i++){ if(flag == 0) break; priority_queue<int,vector<int>,cmp> q; //定義優先隊列 while(!q.empty()) q.pop(); //對每一個點X的終點入隊等待刪邊 for(int j=0; j<G[i].size(); j++){ q.push(G[i][j]); } //只要這個點 X的度數大於R必須刪邊減度 while(degree[i] > r){ int f = 0; //取出隊首 int tp = q.top(); int t = degree[tp]; q.pop(); if(t-1 >= l){ f = 1; degree[tp] --; degree[i]--; }else{ f = 0; } if(degree[tp] >= l+1) q.push(tp); if(f == 0){ flag = 0; break; } } } //一樣的操作,對右邊集合 for(int i=1+offset; i<=m+offset; i++){ if(flag == 0) break; priority_queue<int,vector<int>,cmp> q; while(!q.empty()) q.pop(); for(int j=0; j<G[i].size(); j++){ q.push(G[i][j]); } while(degree[i] > r){ int f = 0; int tp = q.top(); int t = degree[tp]; q.pop(); if(t-1 >= l){ f = 1; degree[tp] --; degree[i]--; } if(degree[tp] >= l+1) q.push(tp); if(f == 0){ flag = 0; break; } } } ///最終判定 if(flag) printf("Case %d: Yes\n" , ca++); else printf("Case %d: No\n" , ca++); } }

2018 ICPC 沈陽網絡預賽 Fantastic Graph (優先隊列)