题目大意:$n$ 个点,$m$ 条边的无向图,边权只有两种,小的为 $a$,大的为 $b$。

对于每个点 $p$,询问在这张图所有的最小生成树上,$1$ 到 $p$ 的最短距离的最小值。

$2\le n\le 70,1\le m\le 200,1\le a<b\le 10^7$。


妙啊,真的太妙了。

有以下几个结论:(以下称边权为 $a$ 的叫轻边,边权为 $b$ 的叫重边)

结论 1:如果原图两个点中存在一条路径只有轻边,那么这两点在所有的最小生成树的路径上都不会有重边。根据最小生成树的性质,显然正确。

结论 2:如果把原图中所有重边删掉,会剩下一些联通块。一条路径可能在最小生成树上,当且仅当它没有离开一个联通块后再回到原来那个联通块中。根据结论 1 这也是对的。(注意,如果两个点属于一个联通块,但是这两个点有重边相连,那这个重边也是不能走的)

那么可以设计状态 $f[S][u]$,$S$ 是已经离开过的联通块集合,$u$ 是目前所在的点。

由于 $f[S][u]$ 可以转移到 $f[S][v]$ 时,$f[S][v]$ 也可以转移到 $f[S][u]$,所以要用最短路的方式更新。

时间复杂度 $O(2^nm\log(2^nm))$。其实由于边权只有两种,可以开两个队列,一个点最多被更新两次,复杂度是 $O(2^nm)$。

然而还有另一个结论:

结论 3:如果一个联通块大小 $\le 3$,那么在 $S$ 中不需要考虑这个联通块。证明,由于离开再回到一个联通块至少要两条重边(除了上面提到的直接一条重边相连,这个可以判掉),而当联通块大小 $\le 3$ 时内部可以通过不超过两条轻边互达。所以即使不记录,最优策略也不会离开再回到这个联通块。

那么只用记录大小 $\ge 4$ 的联通块即可。时间复杂度 $O(2^{n/4}m)$。

细节有点多。

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
char ch=getchar();int x=,f=;
while(ch<'' || ch>'') f|=ch=='-',ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return f?-x:x;
}
int n,m,a,b,w[][],id[],cnt,tmp,f[],q1[],q2[],h1,r1,h2,r2;
bool vis1[],vis2[];
int dfs1(int u){
vis1[u]=true;
int s=;
FOR(i,,n) if(w[u][i]==a && !vis1[i]) s+=dfs1(i);
return s;
}
void dfs2(int u,int c){
vis2[u]=true;
id[u]=c;
FOR(i,,n) if(w[u][i]==a && !vis2[i]) dfs2(i,c);
}
inline int at(int x,int y){return x*n+y-;}
int main(){
n=read();m=read();a=read();b=read();
FOR(i,,m){
int u=read(),v=read();
w[u][v]=w[v][u]=read();
}
FOR(i,,n) if(!vis1[i]) if(dfs1(i)>=) dfs2(i,++cnt);
tmp=cnt;
MEM(vis1,);
FOR(i,,n) if(!vis1[i]) if(dfs1(i)<) dfs2(i,++cnt);
MEM(f,0x7f);
f[at(,)]=;
q1[h1=r1=]=at(,);q2[h2=r2=]=at(,);
while(h1<=r1 || h2<=r2){
int u;
if(h1>r1) u=q2[h2++];
else if(h2>r2) u=q1[h1++];
else if(f[q1[h1]]<f[q2[h2]]) u=q1[h1++];
else u=q2[h2++];
int x=u/n,y=u%n+;
FOR(i,,n){
if(!w[y][i] || (id[i]<=tmp && (x&(<<(id[i]-)))) || (id[i]==id[y] && w[y][i]==b)) continue;
int v;
if(id[y]<=tmp && id[y]!=id[i]) v=at(x|(<<(id[y]-)),i);
else v=at(x,i);
if(f[v]>f[u]+w[y][i]){
f[v]=f[u]+w[y][i];
if(w[y][i]==a) q1[++r1]=v;
else q2[++r2]=v;
}
}
}
FOR(i,,n){
int ans=2e9;
FOR(j,,(<<tmp)-) ans=min(ans,f[at(j,i)]);
printf("%d ",ans);
}
}

CF1149D Abandoning Roads(图论,最短路,状态压缩,最小生成树)的更多相关文章

  1. POJ 3311 Hie with the Pie (BFS+最短路+状态压缩)

    题意:类似于TSP问题,只是每个点可以走多次,求回到起点的最短距离(起点为点0). 分析:状态压缩,先预处理各点之间的最短路,然后sum[i][buff]表示在i点,状态为buff时所耗时...... ...

  2. Light OJ 1316 A Wedding Party 最短路+状态压缩DP

    题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差点儿相同 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两 ...

  3. 最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4568 题目大意: 给一个矩阵 n*m (n m<=200),方格里如果是0~9表示通过它时要花 ...

  4. Codeforces Round #556 CF1149D Abandoning Roads

    这道题并不简单,要得出几个结论之后才可以做.首先就是根据Kruskal求最小生成树的过程,短边是首选的,那么对于这道题也是,我们先做一次直选短边的最小生成树这样会形成多个联通块,这些联通块内部由短边相 ...

  5. hdu 4114 Disney's FastPass(最短路+状态压缩)

    Disney's FastPass Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  6. WOJ 1546 Maze 图论上的状态压缩DP

    http://acm.whu.edu.cn/land/problem/detail?problem_id=1546 这个题目还是聪哥教的方法过的 首先搜索是必须的,而且通过搜索来缩点,这些应该要想到, ...

  7. hdu 2489(状态压缩+最小生成树)

    Minimal Ratio Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  8. Vijos1019 补丁VS错误[最短路 状态压缩]

      描述 错误就是人们所说的Bug.用户在使用软件时总是希望其错误越少越好,最好是没有错误的.但是推出一个没有错误的软件几乎不可能,所以很多软件公司都在疯狂地发放补丁(有时这种补丁甚至是收费的).T公 ...

  9. HDU Victor and World (最短路+状态压缩)

    题目链接:传送门 题意: n个城市m条路.刚開始在点1,求把每一个城市都遍历一边最后回到1的花费的最小值. 分析: ​​+n​2​​∗2​n​​). 转自Bestcode. 以下说说我的状态转移,首先 ...

随机推荐

  1. linux root用户无法删除文件,提示permission denied

    我用root用户登录,删除一个普通的文件,怎么删也删不了.最后用lsattr命令查看,原来是被保护了.lsattr查看一个文件 1. chattr权限简介 chattr - change file a ...

  2. CSS3 clip裁剪动画

    CSS3 clip裁剪动画 下面是比较简单的例子 <pre><html><head><style type="text/css">i ...

  3. 动态html,异步加载页面的处理

    Selenium 基本使用 # 导入 webdriverfrom selenium import webdriver# 调用键盘按键操作时需要引入的Keys包from selenium.webdriv ...

  4. 简述vue props和非props的2个特性

    props的2个特性 ①:父组件通过属性的方式传值(比如下面截图中的content)给子组件,content不会显示在DOM节点中                       ②:父组件向子组件传递值 ...

  5. 关于 NuGet 本地仓库、.NET Core 引用等实战

  6. LeetCode Contest 166

    LeetCode Contest 166 第一次知道LeetCode 也有比赛. 很久没有打过这种线上的比赛,很激动. 直接写题解吧 第一题 很弱智 class Solution { public: ...

  7. 一款常用的截图工具(能够截gif动图)

    这款工具用来截程序的演示GIF图片,灰常方便. 直接上Github地址: https://github.com/NickeManarin/ScreenToGif

  8. Scrapy 运行多个爬虫

    本文所使用的 Scrapy 版本:Scrapy==1.8.0 一个 Scrapy 项目下可能会有多个爬虫,本文陈述两种情况: 多个爬虫 所有爬虫 显然,这两种情况并不一定是等同的.假设当前项目下有 3 ...

  9. 重温CLR(十七)程序集加载和反射

    本章主要讨论在编译时对一个类型一无所知的情况下,如何在运行时发现类型的信息.创建类型的实例以及访问类型的成员.可利用本章讲述的内容创建动态可扩展应用程序. 反射使用的典型场景一般是由一家公司创建宿主应 ...

  10. Python语言获取目录下所有文件

    #coding=utf-8# -*- coding: utf-8 -*-import osimport sysreload(sys) sys.setdefaultencoding('utf-8') d ...