HDU6184 Counting Stars
題意:
Little A is an astronomy lover, and he has found that the sky was so beautiful! So he is counting stars now! There are n stars in the sky, and little A has connected them by m non-directional edges. It is guranteed that no edges connect one star with itself, and every two edges connect different pairs of stars. Now little A wants to know that how many different "A-Structure"s are there in the sky, can you help him? An “A-structure” can be seen as a non-directional subgraph G, with a set of four nodes V and a set of five edges E. If V=(A,B,C,D) and E=(AB,BC,CD,DA,AC), we call G as an “A-structure”. It is defined that “A-structure” G1=V1+E1 and G2=V2+E2 are same only in the condition that V1=V2 and E1=E2.
資料範圍:
Analysis:
翻譯不是這題的重點,我們來講講這題真正要求的東西,其實就是懶得翻譯,英文不好。
事實上就是讓我們三元環計數,找出一條邊存在於多少個三元環中。
我們考慮一種暴力:列舉一個點,列舉所有出邊的點打上標記,再枚舉出邊,然後枚舉出邊的點的出邊,看出邊的點是否有標記,語文功底太差,超級繞 。我們設一個點的出度為,不難發現這樣的複雜度為。讓每條邊只會被列舉兩次。
考慮平衡出度,我們強制讓度數小的連向度數大的點(有向邊),度數相同按編號有序連邊。
不難發現會是一張,因為如果有環的話,編號的偏序關係會矛盾。原先的三元環仍然可以如上列舉,且僅會被列舉一次,因為必定會有且僅有一個點入度為。
這樣複雜度變為,那麼每個點出度為多少呢,是不會超過的。
考慮反證:若一個點出度超過,因為連出去的點出度都大於其,所以至少個點,每個點至少條出邊,出邊總數大於 ,所以與條件矛盾。
那麼總複雜度為。比較優秀,常數也比較小。
至於統計答案,只要算出每條邊存在於多少個三元環,然後加起來就好。
Code:
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
int st[N],to[N << 1],nx[N << 1],id[N << 1];
int vis[N][2],D[N],e[N << 1][2],cnt[N << 1];
int n,m,tot;
inline void add(int u,int v,int w)
{ to[++tot] = v,nx[tot] = st[u],id[tot] = w,st[u] = tot; }
int main()
{
while (~scanf("%d%d",&n,&m))
{
memset(vis,0,sizeof(vis)),memset(st,0,sizeof(st)),memset(cnt,0,sizeof(cnt)),memset(D,0,sizeof(D)),tot = 0;
for (int i = 1 ; i <= m ; ++i) scanf("%d%d",&e[i][0],&e[i][1]),++D[e[i][0]],++D[e[i][1]];
for (int i = 1 ; i <= m ; ++i)
{
if (e[i][0] > e[i][1]) swap(e[i][0],e[i][1]);
if (D[e[i][0]] > D[e[i][1]]) swap(e[i][0],e[i][1]);
add(e[i][0],e[i][1],i);
}
for (int i = 1 ; i <= n ; ++i)
{
for (int j = st[i] ; j ; j = nx[j]) vis[to[j]][0] = i,vis[to[j]][1] = j;
for (int j = st[i] ; j ; j = nx[j])
for (int k = st[to[j]] ; k ; k = nx[k])
if (vis[to[k]][0] == i) ++cnt[id[j]],++cnt[id[k]],++cnt[vis[to[k]][1]];
}
ll ans = 0;
for (int i = 1 ; i <= m ; ++i) if (cnt[i] > 1) ans += (ll)(cnt[i] - 1) * cnt[i] / 2;
printf("%lld\n",ans);
}
return 0;
}