刷这个题之前就觉得自己点双不太会QAQ
最后果然是点双写跪了……
题意与连通性有关+无向图 考虑tarjan->割点
自动想到分情况
对于每一个点双进行考虑
只有一个点肯定要放 方案数1
同理 如果一个割点都没有 需要放两个出口防止其中一个塌了 方案数C(sze,2)
如果只有有一个割点 那么一定要在里面放一个而且除了割点随便放(防止割点塌)方案数sze-1
如果有两个以上割点 那么一个都不用放 因为一个割点塌另一个也可以用
注意:
1.tot初值设为1……
2.我万年不用vector这次都用了(存点双所有点真恶心…)
3.tarjan点双弹栈谈到儿子(Debug的时候样例直接出一个sze=50000…)
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 #include<vector> 7 #define ms(a,b) memset(a,b,sizeof a) 8 #define rep(i,a,n) for(int i = a;i <= n;i++) 9 #define per(i,n,a) for(int i = n;i >= a;i--) 10 #define inf 2147483647 11 using namespace std; 12 typedef long long ll; 13 ll read() { 14 ll as = 0,fu = 1; 15 char c = getchar(); 16 while(c < '0' || c > '9') { 17 if(c == '-') fu = -1; 18 c = getchar(); 19 } 20 while(c >= '0' && c <= '9') { 21 as = as * 10 + c - '0'; 22 c = getchar(); 23 } 24 return as * fu; 25 } 26 const int N = 505; 27 //head 28 int n,m,T; 29 int head[N],nxt[N<<1],mo[N<<1],cnt; 30 void _add(int x,int y) { 31 mo[++cnt] = y; 32 nxt[cnt] = head[x]; 33 head[x] = cnt; 34 } 35 void add(int x,int y){if(x^y)_add(x,y),_add(y,x);} 36 37 int dfn[N],low[N],stk[N],top,idx,scc; 38 bool cut[N]; 39 40 vector<int> mem[N]; 41 42 void tarjan(int x,bool rt) { 43 dfn[x] = low[x] = ++idx; 44 stk[++top] = x; 45 int cld = 0; 46 for(int i = head[x];i;i = nxt[i]) { 47 int sn = mo[i]; 48 if(!dfn[sn]) { 49 tarjan(sn,0); 50 low[x] = min(low[x],low[sn]); 51 if(low[sn] == dfn[x]) { 52 mem[++scc].push_back(x); 53 int t = -1; 54 while(t != sn) { 55 t = stk[top--]; 56 mem[scc].push_back(t); 57 } 58 cld++; 59 cut[x] = 1; 60 } 61 } else low[x] = min(low[x],dfn[sn]); 62 } 63 if(rt && cld < 2) cut[rt] = 0; 64 } 65 66 67 void clr() { 68 rep(i,1,scc) mem[i].clear(); 69 ms(low,0),ms(dfn,0),ms(head,0),ms(cut,0); 70 cnt = top = scc = idx = n = m = 0; 71 } 72 73 ll C2(ll n) {return n*(n-1)/2;} 74 75 void solve() { 76 clr(); 77 m = read(); 78 if(!m) exit(0); 79 rep(i,1,m) { 80 int x = read(); 81 int y = read(); 82 n = max(n,max(x,y)); 83 add(x,y); 84 } 85 int ans = 0; 86 ll tot = 1; 87 rep(i,1,n) if(!dfn[i]) top = 0,tarjan(i,1); 88 rep(i,1,scc) { 89 int num = 0; 90 ll sze = (ll)mem[i].size(); 91 rep(j,0,sze-1) if(cut[mem[i][j]]) num++; 92 if(sze == 1ll) ans++; 93 else if(!num) ans += 2,tot *= C2(sze); 94 else if(num == 1) ans++,tot *= sze - 1; 95 } 96 printf("Case %d: %d %lld ",++T,ans,tot); 97 } 98 99 100 int main() { 101 while(1) solve(); 102 }