@description@

给定一个 n 点 m 条边的无向连通图,每条边的边权为 a 或 b。

对于 1 ~ n 中的每一个 i,求在所有可能的最小生成树中 1 -> i 的最短路的最小值。

Input

第一行包含 4 个整数 n, m, a 与 b (2≤n≤70, n−1≤m≤200, 1≤a<b≤10^7)

接下来 m 行,每行三个整数 u, v, c (1≤u,v≤n, u≠v, c∈{a,b}) 描述了一条带权边 (u, v),其权值为 c。

图连通且无自环重边。

Output

输出一行 n 个整数,第 p 个描述了从 1 到 p 的可能最小值。

Examples

Input

5 5 20 25

1 2 25

2 3 25

3 4 20

4 5 20

5 1 20

Output

0 25 60 40 20

Input

6 7 13 22

1 2 13

2 3 13

1 4 22

3 4 13

4 5 13

5 6 13

6 1 13

Output

0 13 26 39 26 13

@solution@

感觉这道题有一点乱搞.jpg。

考虑 kruskal 求最小生成树的过程:把边按从小到大的顺序尝试加入。

这道题只有两种边权,所以一定是先用边权为 a 的边构成一个森林,再用边权为 b 的边连接这些森林。

一个最短路满足什么条件时不合法?

稍微动手画一画,发现边权为 a 的边并不会影响合法性(可以通过破圈法证明一条简单路径上的 a 边可以同时存在于最小生成树之中)。

不合法的情况只可能因为有些边权为 b 的边不能同时共存于最小生成树中。

什么时候边权为 b 的边不能同时共存?

再联系到我们 kruskal 的过程:假如将 a 边连接的连通块缩点,这些 b 边如果在缩点后的图上形成了环就不合法。

即我们走 b 边不能在以前经过的结点。

状压?但是这是 2^70 啊。

注意到单个结点用不着状压,那么复杂度降到 2^35。

还是很大?继续。2 个结点与 3 个结点也不需要状压:假如形成了环,则可以经过 2 条 b 边从 u -> p -> v。

然而我们内部的 a 边 <= 2 条,走这个内部的 a 边肯定比绕外部的 b 边短,所以最短路不会绕外面。

只有 >= 4 的连通块需要状压,状压部分的复杂度降成 2^17,够了。

那么再套一个 dijkstra 的复杂度,总复杂度为 O(2^(n/4)*m*log(m))。官方题解好像可以更快来着。

不过这个复杂度足够通过本题了。

@accepted code@

#include <cstdio>
#include <queue>
using namespace std;
const int MAXN = 70;
const int MAXM = 200;
const int INF = int(1E9);
struct edge{
int to, dis;
edge *nxt;
}edges[2*MAXM + 5], *adj[MAXN + 5], *ecnt = edges;
void addedge(int u, int v, int w) {
edge *p = (++ecnt);
p->to = v, p->dis = w, p->nxt = adj[u], adj[u] = p;
p = (++ecnt);
p->to = u, p->dis = w, p->nxt = adj[v], adj[v] = p;
}
struct node{
int d, s, x;
node(int _d=0, int _s=0, int _x=0) : d(_d), s(_s), x(_x) {}
friend bool operator < (node a, node b) {
return a.d > b.d;
}
};
bool vis[MAXN][1<<17];
int d[MAXN][1<<17];
priority_queue<node>que;
int dis[MAXN + 5], fa[MAXN + 5], siz[MAXN + 5];
int find(int x) {
return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
void unite(int x, int y) {
int fx = find(x), fy = find(y);
if( fx != fy ) fa[fx] = fy, siz[fy] += siz[fx];
}
int id[MAXN + 5], cnt, tot;
int u[MAXM + 5], v[MAXM + 5], w[MAXM + 5];
int n, m, a, b;
int main() {
scanf("%d%d%d%d", &n, &m, &a, &b);
for(int i=0;i<n;i++) fa[i] = i, siz[i] = 1;
for(int i=1;i<=m;i++) {
scanf("%d%d%d", &u[i], &v[i], &w[i]), u[i]--, v[i]--;
if( w[i] == a )
addedge(u[i], v[i], w[i]), unite(u[i], v[i]);
}
for(int i=0;i<n;i++)
if( find(i) == i ) {
if( siz[i] >= 4 ) id[i] = (cnt++);
else id[i] = -1;
}
for(int i=0;i<n;i++)
id[i] = id[find(i)];
tot = (1<<cnt);
for(int i=0;i<n;i++) {
for(int s=0;s<tot;s++)
d[i][s] = INF;
dis[i] = INF;
}
for(int i=1;i<=m;i++)
if( w[i] == b && find(u[i]) != find(v[i]) )
addedge(u[i], v[i], w[i]);
que.push(node(0, 0, 0));
while( !que.empty() ) {
node x = que.top(); que.pop();
if( vis[x.x][x.s] ) continue;
dis[x.x] = min(dis[x.x], x.d);
vis[x.x][x.s] = true;
for(edge *p=adj[x.x];p;p=p->nxt) {
if( p->dis == a && x.d + p->dis < d[p->to][x.s] )
que.push(node(d[p->to][x.s]=x.d+p->dis, x.s, p->to));
else if( id[p->to] == -1 || !((x.s >> id[p->to]) & 1) ) {
int s = (x.s | (id[x.x] == -1 ? 0 : (1<<id[x.x])));
if( x.d + p->dis < d[p->to][s] )
que.push(node(d[p->to][s]=x.d+p->dis, s, p->to));
}
}
}
for(int i=0;i<n;i++)
printf("%d%c", dis[i], (i == n - 1 ? '\n' : ' '));
}

@details@

n <= 70 你以为是什么多项式算法。

其实这道题是一个 np 问题 2333。

@codeforces - 1149D@ Abandoning Roads的更多相关文章

  1. Codeforces 835 F. Roads in the Kingdom

    \(>Codeforces\space835 F. Roads in the Kingdom<\) 题目大意 : 给你一棵 \(n\) 个点构成的树基环树,你需要删掉一条环边,使其变成一颗 ...

  2. Abandoning Roads CodeForces - 1149D (最小生成树)

    大意: 给定无向图, 边权只有两种, 对于每个点$x$, 输出所有最小生成树中, 点$1$到$x$的最短距离. 先将边权为$a$的边合并, 考虑添加边权为$b$的边. 每条路径只能经过每个连通块一次, ...

  3. Codeforces Round #556 CF1149D Abandoning Roads

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

  4. Codeforces 711D Directed Roads - 组合数学

    ZS the Coder and Chris the Baboon has explored Udayland for quite some time. They realize that it co ...

  5. codeforces 711D Directed Roads(DFS)

    题目链接:http://codeforces.com/problemset/problem/711/D 思路:由于每个点出度都为1,所以没有复杂的环中带环.DFS遍历,若为环则有2^k-2种,若为链则 ...

  6. 【图论】Codeforces 711D Directed Roads

    题目链接: http://codeforces.com/problemset/problem/711/D 题目大意: 给一张N个点N条有向边的图,边可以逆向.问任意逆向若干条边使得这张图无环的方案数( ...

  7. [刷题]Codeforces 746G - New Roads

    Description There are n cities in Berland, each of them has a unique id - an integer from 1 to n, th ...

  8. Codeforces 671 D. Roads in Yusland

    题目描述 Mayor of Yusland just won the lottery and decided to spent money on something good for town. Fo ...

  9. Codeforces 835 F Roads in the Kingdom(树形dp)

    F. Roads in the Kingdom(树形dp) 题意: 给一张n个点n条边的无向带权图 定义不便利度为所有点对最短距离中的最大值 求出删一条边之后,保证图还连通时不便利度的最小值 $n & ...

随机推荐

  1. Hadoop 集群的建立与安装

  2. TZOJ 4292 Count the Trees(树hash)

    描述 A binary tree is a tree data structure in which each node has at most two child nodes, usually di ...

  3. Leetcode405Convert a Number to Hexadecimal数字转换为十六进制数

    给定一个整数,编写一个算法将这个数转换为十六进制数.对于负整数,我们通常使用 补码运算 方法. 注意: 十六进制中所有字母(a-f)都必须是小写. 十六进制字符串中不能包含多余的前导零.如果要转化的数 ...

  4. CF 549B Looksery Party

    题面 解题思路 如果a数组全部>0,那么都不去即可.从这个角度出发,每次选出a[i]为0的,让它们去更新a数组,相当于拓补排序. 代码 #include<iostream> #inc ...

  5. swiper 报错 ‘ Can't find variable: Dom7’

    一般报这个错是因为浏览器兼容问题,例如低版本的IE 现在通过npm install swiper 安装的版本都是4.x的 我的解决方法就是安装低版本的swiper, npm install swipe ...

  6. View的滑动原理和多种滑动方法

    参考链接: http://blog.csdn.net/chunqiuwei/article/details/50679568# http://blog.csdn.net/zly921112/artic ...

  7. [转]web计时机制——performance对象

    页面性能一直都是Web开发人员比较关注的领域.但在实际应用中,度量页面性能的指标,是javascript的Date对象.Web Timing API改变了这个局面,让开发人员通过javascript就 ...

  8. VUE打包好的文件部署让beego实现静态文件访问,如何用根目录来访问静态文件?

    最近的一个全栈项目,光伏云监控系统,后端使用beego框架,纯api,前端使用VUE2.0.项目地址:http://scada.ssechina.com:88/static 我把打包好的前端文件放到g ...

  9. CSS Reset(CSS重置)

    CSS Reset是指重设浏览器的样式.在各种浏览器中,都会对CSS的选择器默认一些数值,譬如当h1没有被设置数值时,显示一定大小. 但并不是所有的浏览器都使用一样的数值,所以有了CSS Reset, ...

  10. neo4j批量导入neo4j-import

    neo4j数据批量导入 1 neo4j基本参数 1.1 启动与关闭: 1.2 neo4j-admin的参数:控制内存 1.2.1 memrec 是查看参考内存设置 1.2.2 指定缓存–pagecac ...