1. 程式人生 > >礦場搭建

礦場搭建

位置 兩個 徹底 space 入口 簡單 line span size

今天我這一臺機器好像不知道怎麽回事,好像被限速了似的。賊慢

今天晚上還有可能回去上萬惡的文化課

我好郁悶呀。

不過今天也終於將點雙和邊雙徹底理解了

%%% tarjan

題目入口

一開始沒有考慮割點能存在於不同的點雙中。

考慮到了以後又在糾結如何計數233

結果發現竟然是最簡單的乘法原理233

割點數量 \(0\) \(1\) \(>=2\)
方案數 \(C^2_n\) \(n-1\) \[0\]

什麽意思呢,當一個點雙中沒有割點時,那麽放哪都可以,不過要放兩個。如果只放一個的話,如果碰巧就是這個塌了。那就GG了

當點雙中只有一個割點時,那麽放在這個點雙的任意一個位置就行了。如果割點被GG了。我們有在點雙中的逃生出口。如果點雙中的逃生出口GG了。我們就可以通過割點溜之大吉。

如果有兩個及以上的割點。因為只會塌方一個,所以無論怎麽塌,都可以轉移到其他的點雙中。就不用再建立了。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int m,n;
int dfn[510],low[510];
int g_num;
vector<int>g[510];
vector<int>l[510];
int t,root;
bool p[510
]; int stack[510],top; void tarjan(int now) { dfn[now]=low[now]=++t; stack[++top]=now; int chi=0; for(int i=0;i<l[now].size();i++) { int nxt=l[now][i]; if(!dfn[nxt]) { chi+=1; tarjan(nxt); low[now]=min(low[now],low[nxt]); if
((now==root&&chi>1)||(now!=root&&dfn[now]<=low[nxt])) p[now]=true; if(low[nxt]>=dfn[now]) { int pas; g_num+=1; do { pas=stack[top--]; g[g_num].push_back(pas); }while(pas!=nxt); g[g_num].push_back(now); } } else low[now]=min(dfn[nxt],low[now]); } } void solve() { for(int i=1;i<=n;i++) g[i].clear(),p[i]=false,l[i].clear(),dfn[i]=0,low[i]=0; n=0; t=0;g_num=0; int a,b; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); l[b].push_back(a); l[a].push_back(b); a=max(a,b); n=max(a,n); } long long set=0,way=1; for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i); for(int i=1;i<=g_num;i++) { int cut=0; for(int j=0;j<g[i].size();j++) if(p[g[i][j]]) cut+=1; int tot=g[i].size(); if(!cut) set+=2ll,way*=1ll*(tot-1)*tot/2; if(cut==1) set+=1ll,way*=1ll*(tot-1); } //printf("%lld %lld\n",set,way); cout<<set<<" "<<way<<endl; } int main() { freopen("input.in","r",stdin); freopen("input.out","w",stdout); scanf("%d",&m); int tot=0; while(m) { printf("Case %d: ",++tot); solve(); scanf("%d",&m); } }

礦場搭建