题意:给你一张图,问最少保留多少条边,使得这张图是边双联通分量。

思路:如果一个点集中的点已经是边双联通分量,那么从这个点集中的点x出发,经过若干个不是点集中的点,回到点集中的点y(x可能等于y),那么这条路径上的点和原来的点就构成了一个新的边双联通分量。

设dp[i]是状态i中的点构成边双联通分量需要的最少的边数,那么我们需要枚举dp[i]的子集,然后判断剩下的点能不能通过一条链串起来,如果可以,那么就是剩下的链的点的个数 + 1.那么怎么知道有没有链呢?这个也需要处理,设dp2[i][j][k]是从i开始,途中经过了点集k中的点,能不能到j(k中不包括i和j),直接dp处理就可以了。

代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define lowbit(x) (x & (-x))
using namespace std;
vector<int> G[14];
int dp[1 << 14], dp2[14][14][1 << 14];
vector<int> re[1 << 14];
pair<int, int> last_pair[1 << 14];
int pre[1 << 14];
int last[14][14][1 << 14];
bool v[1 << 14];
int main() {
int n, m, x, y;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
G[x - 1].push_back(y - 1);
G[y - 1].push_back(x - 1);
}
for (int i = 0; i < n; i++)
v[1 << i] = 1;
memset(dp, 0x3f, sizeof(dp));
dp[1] = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < (1 << n); k++) {
dp2[i][j][k] = INF;
}
for (int i = 0; i < n; i++)
for (auto x : G[i]) {
dp2[i][x][0] = 1;
last[i][x][0] = i;
}
for (int i = 0; i < (1 << n); i++) {
for (int j = 0; j < n; j++) {
if((i >> j) & 1) continue;
for (int k = 0; k < n; k++) {
if((i >> k) & 1) continue;
if(j == k || dp2[j][k][i] == INF) continue;
for (auto z : G[k]) {
if((i >> z) & 1) continue;
if(z == last[j][k][i]) continue;
int tmp = i ^ (1 << k);
if(dp2[j][z][tmp] == INF) {
dp2[j][z][tmp] = 1;
last[j][z][tmp] = k;
}
}
}
}
}
for (int i = 0; i < n; i++)
dp[1 << i] = 0;
// dp[1] = 0;
for (int i = 0; i < (1 << n); i++)
for (int j = 0; j < n; j++) {
if((i >> j) & 1)
re[i].push_back(j);
}
for (int i = 0; i < (1 << n); i++) {
for (int j = i; j; j = (j - 1) & i) {
int tmp = i ^ j;
int cnt = __builtin_popcount(j) + 1;
if(dp[i] < dp[tmp] + cnt) continue;
for (auto x : re[tmp])
for (auto y : re[tmp]) {
if(dp2[x][y][j] == 1) {
dp[i] = min(dp[i], dp[tmp] + cnt);
last_pair[i] = make_pair(x, y);
pre[i] = tmp;
}
}
}
}
if(dp[(1 << n) - 1] == INF) {
printf("-1\n");
} else {
printf("%d\n", dp[(1 << n) - 1]);
int now = (1 << n) - 1;
while(!v[now]) {
int x = last_pair[now].first, y = last_pair[now].second;
int tmp = now ^ pre[now];
while(tmp) {
int tmp1 = last[x][y][tmp];
printf("%d %d\n", y + 1, tmp1 + 1);
y = tmp1;
tmp ^= (1 << tmp1);
}
printf("%d %d\n", x + 1, y + 1);
now = pre[now];
}
}
}

  

Codeforces 1155F 状压DP的更多相关文章

  1. Codeforces 678E 状压DP

    题意:有n位选手,已知n位选手之间两两获胜的概率,问主角(第一个选手)最终站在擂台上的概率是多少? 思路:一看数据范围肯定是状压DP,不过虽然是概率DP,但是需要倒着推:我们如果正着推式子的话,初始状 ...

  2. Codeforces 8C 状压DP

    题意:有个人想收拾行李,而n个物品散落在房间的各个角落里(n < 24).现在给你旅行箱的坐标(人初始在旅行箱处),以及n个物品的坐标,你一次只能拿最多两个物品,并且拿了物品就必须放回旅行箱,不 ...

  3. Codeforces 1215E 状压DP

    题意:给你一个序列,你可以交换序列中的相邻的两个元素,问最少需要交换多少次可以让这个序列变成若干个极大的颜色相同的子段. 思路:由于题目中的颜色种类很少,考虑状压DP.设dp[mask]为把mask为 ...

  4. CodeForces 11D(状压DP 求图中环的个数)

    Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no re ...

  5. codeforces 1185G1 状压dp

    codeforces 1185G1. Playlist for Polycarp (easy version)(动态规划) 传送门:https://codeforces.com/contest/118 ...

  6. Codeforces - 71E 状压DP

    参考官方题解 #include<bits/stdc++.h> #define rep(i,j,k) for(register int i=j;i<=k;i++) #define rr ...

  7. codeforces Diagrams & Tableaux1 (状压DP)

    http://codeforces.com/gym/100405 D题 题在pdf里 codeforces.com/gym/100405/attachments/download/2331/20132 ...

  8. Codeforces Gym 100015F Fighting for Triangles 状压DP

    Fighting for Triangles 题目连接: http://codeforces.com/gym/100015/attachments Description Andy and Ralph ...

  9. Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP

    Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...

随机推荐

  1. Javascript基础三(函数)

    函数第一节: 1.函数的概念及作用     函数是由事件驱动的或者当他被调用时可执行的可重复使用的代码块.   具备一点功能的代码段,代码段来实现具体的功能.要想实现一个函数的功能需要对函数进行调用. ...

  2. activiti 流程部署的各种方式

    流程资源可以是各种类型的文件,在启动流程或流程实例运行过程中会被读取.下面介绍常用的流程资源. 一.流程资源 流程定义文件:扩展名为bpmn20.xml和bpmn; 流程定义的图片:用BPMN2.0规 ...

  3. Linux运维常用脚本整理

    .查找当前目录下占用为0字节的文件并删除 find ./ -type f -size -exec rm -rf {}\;    #此命令不要用于对根目录0字节文件的操作 .将系统进程按内存占用大小排列 ...

  4. JavaSE---Annotation

    1.概述 1.1 JDK1.5开始,java提供了对Annotation的支持: 1.2 Annotation其实就是 代码中的特殊标记,这些标记 可以在编译.类加载.运行时被读取,并执行相应的处理: ...

  5. font-size-adjust属性定义及用法

    font-size-adjust属性定义及用法 在css中,font-size-adjust属性是使用来更好的控制字体大小,当第一个选择的字体不可用时,浏览器使用第二个指定的字体,这可能会导致改变字体 ...

  6. 后端优化(2)—— BA与图优化

  7. Vue - 前端本地项目开发过程中webpack打包内存泄漏问题解决方法

    编译项目出现如下错误: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 原因: n ...

  8. [CSP-S模拟测试51]题解

    错失人生中第一次AK的机会…… A.attack 支配树板子题.考场上发明成功√ 首先支配树上两点路径之间的点都是必经之点,根据这个性质我们就可以yy出建树的方法.跑拓扑,在每个点(设为$x$)即将入 ...

  9. 自定义jQuery Mobile工具栏按钮

    自定义jQuery Mobile工具栏按钮 1.实现效果

  10. 用iptables实现代理上网

    环境:内网:eth1:192.168.2.0/24外网:eth0:10.17.0.111用iptables实现NATSNAT:改变数据包的源地址.防火墙会使用外部地址,替换数据包的本地网络地址.这样使 ...