题意

4.20四川芦山地震发生后,抗震救灾委员会接到一个紧急任务,四川省给该委员会发了一份地图,这份地图给出了该省一些城市的情况:任两个城市是用一条或多条公路连接起来的,也可以没有公路连接,但是每个城市都可以直接或间接地到达另外的城市,注意这些公路是可以双向行驶的。由于最近余震、暴雨造成泥石流倾泻,使得车辆在这些公路上行驶很不安全,于是四川省决定尽快对部分公路进行抢修,以保障救援车辆行车安全。

该省对所有的公路情况都进行了勘察,分析估计了抢修某段公路所需要花费的时间,并记录在地图中。现在该省希望抗震救灾委员会能找到一个方案,该方案决定出哪些公路需要抢修,使得抢修后的公路仍能保证任意两个城市之间都能直接或间接地相连,同时为了安全起见,即使某一条抢修的公路被泥石流阻断了,任意两城市仍能保持这个性质。由于时间紧迫,抗震救灾委员会还需保证找到的这个方案总抢修时间最短。

\(n \leq 12, m \leq 40\)

分析

参照Lethelody的题解。

这道题大意就是:给出一个无向图.求一个权值最小的包含所有点的双联通子图.

定义一些状态:

\(f[i]\):集合状态为\(i\).且使在\(i\)中的点双联通的最小权值.

\(h[i][j][0]\):一个端点是\(j\).另一个端点在点集\(i\)中的边的最小权值.

\(h[i][j][1]\):一个端点是\(j\).另一个端点在点集\(i\)中的边的次小权值.

\(g[i][j][k]\).集合状态为\(i\).且使在\(i\)中的点构成一条链.两端点分别是\(j\)和\(k\)的最小权值.

容易发现.一个边双联通图.必然是由一个双联通的子图和一条链,链的两个端点连向这个连通子图构成的.那么就可以枚举这条链进行转移.

要注意的是:一个点是一个权值为0的双联通图.同时也是一条权值为0的链.

在转移的时候.如果这条链是一个点.转移方程是:

	f[i] = min(f[i], f[t] + g[s][u][u] + h[t][u][0] + h[t][u][1]);

如果这条链的两端点不同.转移方程是:

	f[i] = min(f[i], f[t] + g[s][u][v] + h[t][u][0] + h[t][v][0]);

先预处理出\(h\)和\(g\)数组就好了.

关于\(h\)数组的处理.直接暴力枚举就可以了.

关于\(g\)数组的处理.也是一个状压DP.枚举当前点集i能转移出的状态更新就好了.

时间复杂度\(O(3^n \cdot n^2)\)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<cstring>
#include<cassert>
#define rg register
#define il inline
#define co const
template<class T>T read()
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<class T>T read(T&x)
{
return x=read<T>();
}
using namespace std;
typedef long long ll;
co int INF=0x1f1f1f1f; // edit 2 co int MAXN=12,MAXM=40;
int n,m; struct edge
{
int nx,fr,to,w;
}e[MAXM<<1]; // edit 1
int head[MAXN],ecnt; void addedge(int x,int y,int w)
{
e[++ecnt].fr=x,e[ecnt].to=y,e[ecnt].w=w;
e[ecnt].nx=head[x],head[x]=ecnt;
// cerr<<"ecnt="<<ecnt<<endl;
// assert(-1<=e[ecnt].nx&&e[ecnt].nx<=ecnt);
} int g[1<<MAXN][MAXN][MAXN],h[1<<MAXN][MAXN][2];
int f[1<<MAXN]; void init()
{
memset(g,0x1f,sizeof g);
for(int i=0;i<n;++i)
g[1 << i][i][i]=0;
for(int i=0;i<=ecnt;++i)
{
int x=e[i].fr,y=e[i].to,w=e[i].w;
int s = (1 << x) | (1 << y);
g[s][x][y] = min(g[s][x][y],w);
}
for(int i=1;i<(1<<n);++i)
for(int x=0;x<n;++x)
for(int y=0;y<n;++y)
if(((1 << x) | i) == i && ((1 << y) | i) == i)
for(int k=head[y];k!=-1;k=e[k].nx)
{
assert(-1<=k&&k<=ecnt);
int v=e[k].to,w=e[k].w;
if(((1 << v) | i) != i)
{
int s = (1 << v) | i;
// cerr<<"v="<<v<<endl;
// assert(s<(1<<n));
// assert(s<(1<<n)&&x<n&&v<n&&i<(1<<n)&&y<n);
g[s][x][v] = min(g[s][x][v],g[i][x][y] + w);
}
}
// cerr<<"g end"<<endl;
memset(h,0x1f,sizeof h);
for(int i=1;i<(1<<n);++i)
for(int x=0;x<n;++x)
if(((1 << x) | i) != i)
for(int j=head[x];j!=-1;j=e[j].nx)
{
int y=e[j].to,w=e[j].w;
if(((1 << y) | i) == i)
{
if(w<h[i][x][1])
{
h[i][x][1]=w;
if(h[i][x][1]<h[i][x][0])
swap(h[i][x][1],h[i][x][0]);
}
}
}
} int cnt(int x)
{
int res=0;
while(x)
{
++res;
x-=(x&-x);
}
return res;
} void solve()
{
memset(f,0x1f,sizeof f);
for(int i=0;i<n;++i)
f[1 << i] = 0;
for(int i=1;i<(1<<n);++i)
if(cnt(i)>=2)
for(int s=i&(i-1);s;s=(s-1)&i)
{
int t = i - s;
for(int x=0;x<n;++x)
for(int y=0;y<n;++y)
if(((1 << x) | s) == s && ((1 << y) | s) == s)
{
if(x == y)
f[i] = min(f[i],f[t] + g[s][x][x] + h[t][x][0] + h[t][x][1]);
else
f[i] = min(f[i],f[t] + g[s][x][y] + h[t][x][0] + h[t][y][0]);
}
}
} int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int T=read<int>();
while(T--)
{
memset(head,-1,sizeof head);
ecnt=-1;
read(n);read(m);
for(int i=0;i<m;++i)
{
int x=read<int>()-1,y=read<int>()-1,w=read<int>();
// cerr<<"x="<<x<<" y="<<y<<" w="<<w<<endl;
addedge(x,y,w);
addedge(y,x,w);
}
init();
// cerr<<"init end"<<endl;
solve();
if(f[(1 << n) - 1] < INF)
printf("%d\n",f[(1 << n) - 1]);
else
puts("impossible");
}
return 0;
}

Hint

注意初始值,如果赋成0x3f3f3f3f加4个就会炸int。

BZOJ3590 [Snoi2013]Quare的更多相关文章

  1. 【BZOJ3590】[Snoi2013]Quare 状压DP

    这道题...神题. 首先看到数据范围,一眼状压 dp .然后? 没了. 理性分析,这里说断掉任意一条边图依然连通,即整个图构成一个边双(而不是点双). 之前用 fire (机房里的随机算法总称)之所以 ...

  2. BZOJ 3590: [Snoi2013]Quare

    首先有一个性质,一个双联通图一定可以拆成一个小的双联通子图和一条链 一个点可以视为权值为0的双联通图或者一个点的链 状压DP,枚举子集 O(3^n*n^2) #include<cstdio> ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. BZOJ3590 SNOI2013Quare(状压dp)

    可能作为最优解的边双都可以这样生成:初始时边双内只有一个点,每次选取边双内部两点(可以相同)和一个当前不在边双内的点集,以该两点为起止点找一条链(当然如果两点相同就是个环)将点集串起来,加入边双.状压 ...

  5. [ SNOI 2013 ] Quare

    Description 题目链接 求一张无向带权图的边双连通生成子图的最小代价. Solution 核心的思路是,一个点双连通分量肯定是一堆环的并. 考虑增量地构造这个边双连通图,每次把一个环并进去, ...

  6. MapReduce的C#实现及单元测试(试验)

    MapReduce.cs类文件代码  MapReduce的执行方法 using System; using System.Collections.Generic; //using System.Lin ...

  7. 苹果新的编程语言 Swift 语言进阶(十四)--扩展

    扩展是为一个已经存在的类.结构.枚举类型添加新功能的一种方式,包括为不能存取源代码的那些已经存在的类型添加功能. 扩展类似于Objective-C语言中的类别,与类别不同的是Swift语言的扩展没有名 ...

  8. F#注解

    不要问我为啥要学F#——因为气质摆在那里 标注:以下内容均来自 anderslly F#系列 1.类型推演 let square x = x * x //接受一个某类型参数的quare函数返回一个这个 ...

  9. 对MBProgressHUD进行二次封装并精简使用

    对MBProgressHUD进行二次封装并精简使用 https://github.com/jdg/MBProgressHUD 几个效果图: 以下源码是MBProgressHUD支持最新的iOS8的版本 ...

随机推荐

  1. MySQL5.7 半同步复制

    一.概述 5.5与5.7的半同步复制可能存在差异,从MySQL5.5开始,MySQL以插件的形式支持半同步复制 异步:默认情况下,MySQL复制是异步的.主库在执行完客户端提交的事务后会立即将结果返给 ...

  2. vs2012 在调试或运行的过程中不能加断点

    在使用VS2012 的过程中,突然发现在调试的过程中,不能加断点,显示断点未能绑定.在搜寻了很多解决方案后未能解决,3.23这一天,重装了VS也没有用. 便想着把网上所有的方法都试个遍也要解决这个问题 ...

  3. 重新学习MySQL数据库2:『浅入浅出』MySQL 和 InnoDB

    重新学习Mysql数据库2:『浅入浅出』MySQL 和 InnoDB 作为一名开发人员,在日常的工作中会难以避免地接触到数据库,无论是基于文件的 sqlite 还是工程上使用非常广泛的 MySQL.P ...

  4. clipboard.js使用方法

    HTML data-clipboard-action=“ copy ”  或者“cut” data-clipboard-target="#domName" data-clipboa ...

  5. 应用性能管理工具PinPoint介绍

    概述: 下面介绍一个开源的 APM (Application Performance Management/应用性能管理)工具 - Pinpoint.一个分布式事务跟踪系统的平台,思路基于google ...

  6. Python 序列化pickle/cPickle模块整理

    Python序列化的概念很简单.内存里面有一个数据结构,你希望将它保存下来,重用,或者发送给其他人.你会怎么做?这取决于你想要怎么保存,怎么重用,发送给谁.很多游戏允许你在退出的时候保存进度,然后你再 ...

  7. 在 Bash on Ubuntu 上安装Nginx

    前言 Win10 上的 Bash on Ubuntu 是个很好用的玩具,让windows开发环境下的人能无缝操练Linux,但是涉及到网络部分还是有很多要该进的地方,比如Nginx的安装就遇到了问题. ...

  8. 【前端工具】seajs打包部署工具spm的使用总结

    相信使用seajs的好处大家都是知道的,接触seajs好像是在半年前,当时还不知道页面阻塞问题,这里不带多余的话了. seajs实现了模块化的开发,一个网站如果分了很多很多模块的话,等开发完成了,发现 ...

  9. ant+jmeter+jenkins+git持续集成以及邮件报告展示

    前序准备工作: ant--下载地址:http://ant.apache.org/bindownload.cgi jmeter--下载地址:http://jmeter.apache.org/downlo ...

  10. C++11_ Lambda

    版权声明:本文为博主原创文章,未经博主允许不得转载. 这次主要介绍C++11的Lambda语法,一个非常给力的语法 1.组成 : [...导入符号](...参数)mutable(可改写)  throw ...