POJ 2942 Knights of the Round Table (算竞进阶习题)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                POJ 2942 Knights of the Round Table (算竞进阶习题)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                很巧的一道點雙
兩個騎士如果相互憎恨,我們考慮連邊的話,不太好處理答案,所以我們嘗試一下建反圖。
如果兩個騎士沒有相互憎恨,我們就在他們兩個人之間連一條無向邊,最后要讓你會議召開,那么顯然是選擇任意一個奇環上的所有點。
現在題目就變成了找不在奇環上的點的個數。
有引理:
- 若兩個點屬于不同的點雙,則他們不可能在同一個奇環。 
- 若某個點雙內存在奇環,則這個點雙的所有點必定被至少一個奇環包含。 
綜上所述,奇環只會在點雙內,所以我們把反圖的點雙找出來,一個一個判斷是否存在奇環即可(只要存在奇環,這個點雙內的所有點一定有辦法參加會議, 因為總有一個奇環會包含點雙內的一些點,這所有奇環的并集就是點雙內的所有點)。
對于判斷一張圖是否存在奇環,實際上就是判斷一張圖是不是二分圖,因為二分圖是不可能存在奇環的,存在奇環的圖也一定不是二分圖。
最后統計不在奇環的點即可。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){int X = 0, w = 0; char ch = 0;while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){A ans = 1;for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;return ans;
}
const int N = 1005;
int n, m, cnt, k, root, tot, head[N], dfn[N], low[N], cut[N], col[N], c[N];
bool has[N][N], able[N], flag;
vector<int> dcc[N];
stack<int> st;
struct Edge { int v, next; } edge[2000005];void addEdge(int a, int b){edge[cnt].v = b, edge[cnt].next = head[a], head[a] = cnt ++;
}void build(){while(!st.empty()) st.pop();cnt = k = tot = 0;full(has, false), full(head, -1);full(dfn, 0), full(low, 0);full(cut, false), full(able, false);full(col, 0), full(c, 0);for(int i = 1; i <= n; i ++)dcc[i].clear();
}void tarjan(int s){dfn[s] = low[s] = ++k;st.push(s);if(s == root && head[s] == -1){dcc[++tot].push_back(s);return;}int flag = 0;for(int i = head[s]; i != -1; i = edge[i].next){int u = edge[i].v;if(!dfn[u]){tarjan(u);low[s] = min(low[s], low[u]);if(low[u] >= dfn[s]){flag ++;if(s != root || flag > 1) cut[s] = true;tot ++;int cur;do{cur = st.top(); st.pop();dcc[tot].push_back(cur);}while(cur != u);dcc[tot].push_back(s);}}else low[s] = min(low[s], dfn[u]);}
}bool dfs(int s, int color, int cur){col[s] = color;for(int i = head[s]; i != -1; i = edge[i].next){int u = edge[i].v;if(c[u] != cur) continue;if(col[u] == color) return false;if(!col[u] && !dfs(u, 3 - color, cur)) return false;}return true;
}int main(){ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);while(cin >> n >> m && n && m){build();for(int i = 0; i < m; i ++){int u, v;cin >> u >> v;has[u][v] = has[v][u] = true;}for(int i = 1; i < n; i ++){for(int j = i + 1; j <= n; j ++)if(!has[i][j]) addEdge(i, j), addEdge(j, i);}for(int i = 1; i <= n; i ++){if(!dfn[i]) root = i, tarjan(i);}for(int i = 1; i <= tot; i ++){for(int j = 0; j < dcc[i].size(); j ++){c[dcc[i][j]] = i, col[dcc[i][j]] = 0;}if(!dfs(dcc[i][0], 1, i)){for(int j = 0; j < dcc[i].size(); j ++){able[dcc[i][j]] = true;}}}int ans = 0;for(int i = 1; i <= n; i ++){if(!able[i]) ans ++;}printf("%d\n", ans);}return 0;
}轉載于:https://www.cnblogs.com/onionQAQ/p/10840812.html
總結
以上是生活随笔為你收集整理的POJ 2942 Knights of the Round Table (算竞进阶习题)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 我要肖申克的救赎的资源
- 下一篇: 个性的qq签名
