P6815 [PA2009]Cakes
ker_xyxyxyx_xxs · · 题解
P6815 [PA2009]Cakes
题目直接点出三元环了,简单介绍一下。
定义:三元环是指对于图上的三个点,两两点之间都直接有边相连,这三个点组成的环就是三元环。
三元环的计数方法:记录图中每个点的度数,对于每条边将它定向。对于一条边,将度数大的点指向度数小的点,如果度数相同就将编号小的点指向编号大的点。计数时枚举每个点,对于每个点 x 枚举它的出边,并将出边指向的点 y 打标记,对于所有出边指向的点 y 再枚举出边,如果这个出边指向的点 z 被打了标记,那么 x,y,z 就组成了一个三元环。时间复杂度为
性质:
1、这一定是一个有向无环图。
2、每个三元环只会被统计一次。
(怎么证明请自己思考)
这个题直接按照上述方法计算即可。
AC 100pts Code
# include <iostream>
# include <cstdio>
# include <vector>
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
#define putchar(x) (p3-obuf<1000000)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
template<typename item>
inline void read(register item &x)
{
x=0;register char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
static char cc[10000];
template<typename item>
inline void print(register item x)
{
register long long len=0;
while(x)cc[len++]=x%10+'0',x/=10;
while(len--)putchar(cc[len]);
}
const int maxn = 2e6 + 5;
typedef long long ll;
ll ans = 0;
int n , m;
int w[maxn];
typedef struct {
int x , y;
}ed;
ed N[maxn];
int x , y;
vector<int> g[maxn];
int deg[maxn];
int mark[maxn];
int main() {
read(n);
read(m);
for (int i = 1 ; i <= n ; i ++) {
read(w[i]);
}
for (int i = 1 ; i <= m ; i ++) {
read(x);
read(y);
deg[x] ++;
deg[y] ++;
N[i].x = x;
N[i].y = y;
}
for (int i = 1 ; i <= m ; i ++) {
int x = N[i].x , y = N[i].y;
if (deg[x] > deg[y] || (deg[x] == deg[y] && x < y)) swap(x , y);
g[x].push_back(y);
}
for (int x = 1 ; x <= n ; x ++) {
for (int i = 0 ; i < g[x].size() ; i ++) {
mark[g[x][i]] = x;
}
for (int i = 0 ; i < g[x].size() ; i ++) {
int e = g[x][i];
for (int j = 0 ; j < g[e].size() ; j ++) {
int endd = g[e][j];
if (mark[endd] == x) ans += max(w[x] , max(w[e] , w[endd]));
}
}
}
printf("%lld\n" , ans);
fwrite(obuf,p3-obuf,1,stdout);
return 0;
}