BZOJ 2730 礦場搭建
阿新 • • 發佈:2019-04-29
++ 聯通 amp getchar() sca template str 範圍 for
割點
割點意外的點坍塌不影響結果,因為假設我們任取連個個非割點s建立救援站,非割點的任意點坍塌,我們都可以從割點走到一個救援出口。
所以我們只考慮割點坍塌的情況。
我們可以先找出圖中所有的割點。
假如圖中沒有割點,那麽肯定需要兩個救援出口才能保證有路走。
假如有割點,對於每個不含割點的聯通塊,若該聯通塊只與一個割點相連,那麽則需要選擇該聯通塊中的一個點建立救援出口;若該聯通塊與兩個以上割點相連,那麽這塊聯通塊裏則不需要建立救援出口。
數據範圍很小,隨便搞搞!
#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 = 1000; int n, m, cnt, k, root, tot, c, head[N], dfn[N], low[N], scc[N], rd[N]; bool vis[N], cut[N]; struct Edge { int v, next; } edge[N<<2]; void addEdge(int a, int b){ edge[cnt].v = b, edge[cnt].next = head[a], head[a] = cnt ++; } void init(){ full(head, -1), full(cut, false), full(dfn, 0), full(low, 0); full(scc, 0), full(rd, 0); cnt = 0, tot = 0, k = 0, n = 0; } void tarjan(int s){ dfn[s] = low[s] = ++k; 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; } } else low[s] = min(low[s], dfn[u]); } } void dfs(int s){ vis[s] = true; if(!scc[s]) scc[s] = tot; else scc[s] = -1; for(int i = head[s]; i != -1; i = edge[i].next){ int u = edge[i].v; if(!vis[u] && !cut[u]) dfs(u); } } int main(){ while(~scanf("%d", &m) && m){ init(); for(int i = 0; i < m; i ++){ int s = read(), t = read(); addEdge(s, t), addEdge(t, s); n = max(s, t, n); } for(int i = 1; i <= n; i ++){ if(!dfn[i]) root = i, tarjan(i); } for(int s = 1; s <= n; s ++){ if(cut[s]){ full(vis, false); for(int i = head[s]; i != -1; i = edge[i].next){ int u = edge[i].v; if(!cut[u] && !vis[u]) tot ++, dfs(u); } } } for(int i = 1; i <= n; i ++){ if(scc[i] != -1) rd[scc[i]] ++; } int p = 0; ll tmp = 1; for(int i = 1; i <= tot; i ++){ if(rd[i]) p ++, tmp *= rd[i]; } if(!p) printf("Case %d: 2 %lld\n", ++c, (ll)(n * (n - 1) / 2)); else printf("Case %d: %d %lld\n", ++c, p, tmp); } return 0; }
BZOJ 2730 礦場搭建