1. 程式人生 > >P3225 [HNOI2012]礦場搭建 tarjan割點

P3225 [HNOI2012]礦場搭建 tarjan割點

algorithm 救援 tar efi cut 決定 dfs spa pre

這個題需要發現一點規律,就是先按割點求塊,然後求每個聯通塊中有幾個割點,假如沒有割點,則需要建兩個出口,如果一個割點,則需要建一個出口,2個以上不用建。

題幹:

題目描述

煤礦工地可以看成是由隧道連接挖煤點組成的無向圖。為安全起見,希望在工地發生事故時所有挖煤點的工人都能有一條出路逃到救援出口處。於是礦主決定在某些挖煤點設立救援出口,使得無論哪一個挖煤點坍塌之後,其他挖煤點的工人都有一條道路通向救援出口。

請寫一個程序,用來計算至少需要設置幾個救援出口,以及不同最少救援出口的設置方案總數。
輸入輸出格式
輸入格式:

輸入文件有若幹組數據,每組數據的第一行是一個正整數 N(N
<=500),表示工地的隧道數,接下來的 N 行每行是用空格隔開的兩個整數 S 和 T,表示挖 S 與挖煤點 T 由隧道直接連接。輸入數據以 0 結尾。 輸出格式: 輸入文件中有多少組數據,輸出文件 output.txt 中就有多少行。每行對應一組輸入數據的 結果。其中第 i 行以 Case i: 開始(註意大小寫,Case 與 i 之間有空格,i 與:之間無空格,: 之後有空格),其後是用空格隔開的兩個正整數,第一個正整數表示對於第 i 組輸入數據至少需 要設置幾個救援出口,第二個正整數表示對於第 i 組輸入數據不同最少救援出口的設置方案總 數。輸入數據保證答案小於 2^64。輸出格式參照以下輸入輸出樣例。

代碼:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;++i)
#define lv(i,a,n) for(register int i = a;i >= n;--i)
#define
clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; #define int long long typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < 0 || c > 9) if(c == -) op = 1; x = c - 0; while(c = getchar(), c >= 0 && c <= 9) x = x * 10 + c - 0; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(-), x = -x; if(x >= 10) write(x / 10); putchar(0 + x % 10); } const int N = 505; int dfn[N],vis[N],low[N]; bool cut[N]; int num,Cut,tim,root,rs,m,n,ans1,ans2,Case,group; struct node { int l,r,nxt; }a[N * N]; int lst[N],len = 0; void add(int x,int y) { a[++len].l = x; a[len].r = y; a[len].nxt = lst[x]; lst[x] = len; } void tarjan(int x,int fa) { dfn[x] = low[x] = ++tim; for(int k = lst[x];k;k = a[k].nxt) { int y = a[k].r; if(!dfn[y]) { tarjan(y,x); low[x] = min(low[x],low[y]); if(low[y] >= dfn[x]) { if(x != root) cut[x] = true; else rs++; } } else { if(y != fa) low[x] = min(low[x],dfn[y]); } } } void dfs(int x) { vis[x] = group; num++; for(int k = lst[x];k;k = a[k].nxt) { int y = a[k].r; if(cut[y] && vis[y] != group) { Cut++; vis[y] = group; } if(!vis[y]) dfs(y); } } void init() { clean(vis); clean(dfn); clean(lst); clean(low); clean(cut); len = 0;ans1 = group = 0;num = 0; ans2 = 1;n = 0;tim = 0;Cut = 0; } main() { int u,v; Case = 1; while(cin>>m && m) { init(); duke(i,1,m) { read(u);read(v); add(u,v); add(v,u); n = max(n,max(u,v)); } for(int i = 1;i <= n;i++) { if(!dfn[i]) { root = i; rs = 0; tarjan(i,i); if(rs >= 2) cut[i] = true; } } duke(i,1,n) { if(!vis[i] && !cut[i]) { ++group; num = Cut = 0; dfs(i); if(Cut == 0) { ans1 += 2; ans2 *= (num - 1) * num / 2; } if(Cut == 1) { ans1 += 1; ans2 *= num; } } } printf("Case %lld: %lld %lld\n",Case++,ans1,ans2); } return 0; }

P3225 [HNOI2012]礦場搭建 tarjan割點