首先可以发现的是,因为两条线段不能在除了端点处相交,因此整个多边形最终一定会被连接成最上方由若干条线段在端点处相交连成,每条线段下方又是一个子结构。

因此你会发现,每个合法的状态都能被分成两个合法的子结构,因此可以考虑使用区间 \(dp\) 来解决这个问题。

首先,我们简单地考虑令 \(dp_{i, j}\) 表示只使用 \(i, j\) 这个区间之间的边将 \(i, j\) 这个区间联通的方案。

  • 直接在 \(i, j\) 之间连边。

那么枚举每个 \(k\) 做为中间的断点,那么就有转移:

\[dp_{i, j} = \sum\limits_{k = i} ^ {j - 1} dp_{i, k} \times dp_{k + 1, j}(a_{i, j} = 1)
\]
  • 不直接在 \(i, j\) 之间连边。

同样考虑枚举中间的端点 \(k\),那么一个合法的方案就会被描述为用 \(i \sim k\) 之间的边联通 \(i \sim k\) 另一边类似,于是有转移:

\[dp_{i, j} = \sum\limits_{k = i + 1} ^ {j - 1} dp_{i, k} \times dp_{k, j}
\]

但其实你会发现,同一个断点的方案会被所有最外层线段交点的位置计算一次,那么一个最简单的想法就是让这个方案只被计算一次。

于此同时你可以发现我们目前只会计算直接连接两个端点的方案,因此让这个方案在左上边第一个线段交点的位置计算一次是一个不赖的选择。

因此我们需要改写一下 \(dp\) 的状态,令 \(dp_{i, j, 0 / 1}\) 分别表示直接连接 \(i, j\) 和不直接连接 \(i, j\) 的方案。

那么这里的转移就应该变为:

\[dp_{i, j, 1} = \sum\limits_{k = i + 1} ^ {j - 1} (dp_{i, k, 0} + dp_{i, k, 1}) \times dp_{k, j, 0}
\]

对应地改写第一条转移方程即可。

复杂度 \(O(n ^ 3)\)。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 500 + 5;
const int Mod = 1e9 + 7;
int n, a[N][N], f[N][N], dp[N][N][2];
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int Inc(int a, int b) { return (a += b) >= Mod ? a - Mod : a;}
int Mul(int a, int b) { return 1ll * a * b % Mod;}
int main() {
n = read();
rep(i, 1, n) rep(j, 1, n) a[i][j] = read();
rep(i, 1, n) dp[i][i][1] = f[i][i] = 1;
rep(i, 1, n) dp[i][i + 1][0] = f[i][i + 1] = a[i][i + 1];
rep(len, 3, n) rep(i, 1, n) {
int j = i + len - 1; if(j > n) break;
rep(k, i, j - 1) if(a[i][j]) dp[i][j][0] = Inc(dp[i][j][0], Mul(f[i][k], f[k + 1][j]));
rep(k, i + 1, j - 1) dp[i][j][1] = Inc(dp[i][j][1], Mul(f[i][k], dp[k][j][0]));
f[i][j] = Inc(dp[i][j][0], dp[i][j][1]);
}
printf("%d", f[1][n]);
return 0;
}

值得一提的是,\(dp\) 的转移一定要想办法将这个问题拆解成已经解决的子问题的结构,例如区间 \(dp\) 中就一定要能描述为左右两个合法区间的结合或其他的意义。

CF888F Connecting Vertices的更多相关文章

  1. Connecting Vertices CodeForces - 888F (图论,计数)

    链接 大意: 给定邻接表表示两点是否可以连接, 要求将图连成树, 且边不相交的方案数 n范围比较小, 可以直接区间dp $f[l][r]$表示答案, $g[l][r]$表示区间[l,r]全部连通且l, ...

  2. POJ Minimum Cut

    Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 9302   Accepted: 3902 Case ...

  3. POJ 2914 Minimum Cut

    Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 9319   Accepted: 3910 Case ...

  4. 论文笔记之:Large Scale Distributed Semi-Supervised Learning Using Streaming Approximation

    Large Scale Distributed Semi-Supervised Learning Using Streaming Approximation Google  2016.10.06 官方 ...

  5. CodeForces 682C Alyona and the Tree (树+dfs)

    Alyona and the Tree 题目链接: http://acm.hust.edu.cn/vjudge/contest/121333#problem/C Description Alyona ...

  6. POJ_2914_Minimum_Cut_(Stoer_Wagner)

    描述 http://poj.org/problem?id=2914 求无向图中最小割. Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K T ...

  7. POJ 2914 Minimum Cut 最小割图论

    Description Given an undirected graph, in which two vertices can be connected by multiple edges, wha ...

  8. Shorten Diameter

    Shorten Diameter Time limit : 2sec / Stack limit : 256MB / Memory limit : 256MB Score : 600 points P ...

  9. 2015 多校联赛 ——HDU5302(构造)

    Connect the Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

随机推荐

  1. Deep Residual Learning for Image Recognition (ResNet)

    目录 主要内容 代码 He K, Zhang X, Ren S, et al. Deep Residual Learning for Image Recognition[C]. computer vi ...

  2. pycharm遇到的小问题

    1. Pycharm编写的代码出现满屏的波浪线,如何去除>>>点击右下角的小人图标将箭头移到中间syntax处即可. 2. 运行时报错: UserWarning: No parser ...

  3. 前后端java+vue 实现rsa 加解密与摘要签名算法

    RSA 加密.解密.签名.验签.摘要,前后端java+vue联调测试通过 直接上代码 // 注意:加密密文与签名都是唯一的,不会变化.// 注意:vue 端密钥都要带pem格式.java 不要带pem ...

  4. JDK线程池异常处理方式

    1. 抛出异常 execute() java.util.concurrent.ThreadPoolExecutor#runWorker 中抛出,抛出之后经过以下两个步骤: catch块捕获,捕获之后再 ...

  5. AWS修改RDS时区

    查看 RDS 当前时区 默认情况下,AWS 的 RDS 采用的是 UTC 时间.而我们地区一般位于东八区,因此我们本地的时间是 UTC+8. 连接到 RDS 上,查询当前实例的时区. show var ...

  6. TYPESCRIPT中文教程基础部分下----翻译自TS官方

    type 别名 我们已经使用过 object 和 联合的方式 直接声明类型.但是某个类型在使用多次的情况下就要用到别名了. 别名的语法就像是在定义一个具名的对象一样: type Point = { x ...

  7. 获取python的版本

    import sys # Syntax sugar. _ver = sys.version_info # 获取python版本 #: Python 2.x? is_py2 = (_ver[0] == ...

  8. CentOS7 安装mysql并解决安装慢的问题

    0.centOS7 mini版安装及网络配置 //可从我的网盘保存下载,可用虚拟机安装 链接:https://pan.baidu.com/s/10_AHxN0DtJ75s1oFOaaZ3A 密码:ud ...

  9. antd-vue中的form表单label标签for导致点击文字触发输入框解决方案

    <a-form-item :label="label+'图片'" :label-col="{ span: 2 }" :wrapper-col=" ...

  10. react中create-react-app配置antd按需加载(方法二)

    1.yarn add babel-plugin-import 2.在根目录下的package.json下的bable中添加相应代码 "babel": { "presets ...