POJ - 2942 Knights of the Round Table(点双缩点+二分图判定)
題目鏈接:點擊查看
題目大意:國王要在圓桌上召開騎士會議,但是有若干對騎士之間互相憎恨。出于各種各樣奇怪的原因,每次開會都必須有以下要求:
如果有某個騎士無法出席任何會議,則國王會為了世界和平把他踢出騎士團。現在給定n個騎士和m個憎恨關系,求出至少需要踢掉多少個騎士
題目分析:很綜合的一道圖論題目,首先我們需要先將模型提取出來,因為n至多有1e3個,所以整個圖最多有1e6條邊,方便處理起見我們可以直接用鄰接矩陣存邊,對于m個憎恨關系,我們可以對其建立補圖,也就是哪些騎士可以互相挨在一起,而題目的要求是一個圓形的桌子,并且是要有奇數個騎士,所以必須滿足可以構成奇環的點才可以留下來,至于找奇環,因為對于二分圖的定義是這樣寫的:
一張無向圖是二分圖,當且僅當圖中不存在奇環(長度為奇數的環)
這樣我們判斷是否有奇環的方法就可以直接用二分圖染色判定了
這里需要引進幾個引理,證明就不放了,因為放了我也看不懂:
有了上述兩個引理,現在問題就轉換為了在每一個點雙連通分量中判斷是否存在奇環,因為割點可以同時屬于多個點雙聯通分量,一開始我就感覺如果用鄰接表來寫的話會有很多細節需要處理,于是就直接用鄰接矩陣實現的,多開了一個book數組用來判斷哪些點可以組成奇環,可以組成奇環的點標記一下,等處理完所有點后,最后找出有多少個點沒有被標記過,也就是不被任何一個奇環包含,統計一下這些點的個數就是最終答案了
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100;int low[N],dfn[N],Stack[N],color[N],num,cnt,tot,root,top,n,m;bool cut[N],maze[N][N],book[N],alone[N];vector<int>dcc[N];void tarjan(int u) {dfn[u]=low[u]=++num;Stack[++top]=u;if(u==root&&alone[u]){dcc[++cnt].push_back(u);return;}int flag=0;for(int v=1;v<=n;v++){if(!maze[u][v])continue;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]){flag++;if(u!=root||flag>1)cut[u]=true;cnt++;int x;do{x=Stack[top--];dcc[cnt].push_back(x);}while(x!=v);dcc[cnt].push_back(u);}}elselow[u]=min(low[u],dfn[v]);} }void solve() {for(int i=1;i<=n;i++)//找割點+縮點 if(!dfn[i]){root=i;tarjan(i);} }bool dfs(int u,int c,int id)//二分圖的染色法判定 {color[u]=c;for(int i=0;i<dcc[id].size();i++){int v=dcc[id][i];if(!maze[u][v])continue;if(color[v]==-1&&!dfs(v,!c,id))return false;else if(color[v]==c)return false;}return true; }void cal()//遍歷每一個點雙連通分量,找奇環 {for(int i=1;i<=cnt;i++){memset(color,-1,sizeof(color));if(!dfs(dcc[i][0],0,i)){for(int j=0;j<dcc[i].size();j++)book[dcc[i][j]]=true;}} }bool check(int x)//檢查一下點x是否為孤點 {for(int i=1;i<=n;i++)if(maze[x][i])return false;return true; }void Alone()//標記孤點 {for(int i=1;i<=n;i++)if(check(i))alone[i]=true; }void init() {for(int i=0;i<N;i++)dcc[i].clear();for(int i=0;i<N;i++)for(int j=0;j<N;j++)maze[i][j]=i==j?false:true;cnt=num=tot=top=0;memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(cut,false,sizeof(cut));memset(Stack,0,sizeof(Stack));memset(book,false,sizeof(book));memset(alone,false,sizeof(alone)); }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF&&n+m){init();while(m--){int u,v;scanf("%d%d",&u,&v);maze[u][v]=maze[v][u]=false;}Alone();solve();cal();int ans=0;for(int i=1;i<=n;i++)//統計一下哪些點沒有被奇環包含if(!book[i])ans++;printf("%d\n",ans);}return 0; }?
總結
以上是生活随笔為你收集整理的POJ - 2942 Knights of the Round Table(点双缩点+二分图判定)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 4738 Caocao's
- 下一篇: POJ - 2230 Watchcow(