您的位置:首页 > 编程语言 > Go语言

Codeforces 51E Pentagon - 组合数学 - 动态规划

2018-03-08 07:50 381 查看
题目传送门

  传送门I

  传送门II

题目大意

  给定一个$n$个点,$m$条边的无向图,问图中有多少个大小为$5$的简单环。

  $5 = 2 + 3$。因此,可以把一个五元环分成$u$到$v$的长度为$2$的路径以及长度为$3$的路径。

  对于定起点和终点长度为$2$的路径数可以用类似于Floyd的思想来进行动态规划求解,对于长度为$3$的路径同理。  

  枚举$u$,$v$然后计算数量($u = v$是允许的)。但是这样会算重以及算到不合法情况,然后依次考虑每种情况。

合法情况



任意一对距离为2的点对会对它造成1次贡献,这样的有序点对一共有10对。
所以总共会造成10次贡献。

不合法情况I



这是一个三元环再加上1个点。点对$(1, 3), (1, 4), (2, 3), (2, 4)$以及它们交换前后顺序后分别会对答案造成1次贡献,点对$(2, 2)$会对答案有2次贡献。
总共造成10次贡献

不合法情况II



这是一个三元环。点对$(1, 2), (1, 3), (2, 3)$以及他们交换前后顺序后分别会对答案造成3次贡献(例如$1-3-1-2$和$1-3-2$,$1 - 2 - 3 - 2$和$1 - 3 - 2$以及$1 - 2 - 1 - 2$和$1 - 3 - 2$),点对$(1, 1)$, $(2, 2)$, $(3, 3)$分别会对答案造成$2 \times 2 = 4$次贡献。
总共是$3 \times 2 \times 3 + 3 \times 4 = 30$次贡献。这里一共有3条边。

  所以综上所述,每造成10次不合法情况的贡献是因为一个三元环再加上一条边。

  所以可以先计算每个点的度数,然后枚举这个三元环来扣除不合法情况。

Code

/**
* Codeforces
* Problem#51E
* Accepted
* Time: 8796ms
* Memory: 13692k
*/
#include <bits/stdc++.h>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;

const int N = 705;

#define ll long long

int n, m;
int deg
;
ll f[3]

;

inline void init() {
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++) {
scanf("%d%d", &u, &v);
deg[u]++, deg[v]++;
f[0][u][v] = f[0][v][u] = 1;
}
}

inline void solve() {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
f[1][i][j] += f[0][i][k] * f[0][k][j];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
f[2][i][j] += f[0][i][k] * f[1][k][j];

ll ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
ans += f[1][i][j] * f[2][i][j];

ans /= 10;

for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
if (f[0][i][j])
for (int k = j + 1; k <= n; k++)
if (f[0][j][k] && f[0][i][k])
ans -= deg[i] + deg[j] + deg[k] - 3;
printf(Auto"\n", ans);
}

int main() {
init();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: