礦場搭建
阿新 • • 發佈:2018-06-26
位置 兩個 徹底 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);
}
}
礦場搭建