这道题并不简单,要得出几个结论之后才可以做。首先就是根据Kruskal求最小生成树的过程,短边是首选的,那么对于这道题也是,我们先做一次直选短边的最小生成树这样会形成多个联通块,这些联通块内部由短边相连。那么接下来要形成完整的最小生成树,我们就得用长边把这些联通块连起来,因为要最短路径,所以我们用Dijkstra做连边的过程 这里给出一个结论:只要满足两个条件:第一,每个联通块内部不能连长边。第二,一个联通块不能被访问两遍。

重点来了:只要是满足这两个条件下树就能保证它是一棵最小生成树。

为什么呢?因为我们已经把所有能连的短边连起来了,接下来的联通块必须的用长边连起来,连起来之后就是用了尽量多的短边和尽量少的长边生成的树,那当然是最小生成树。

那为什么又要用最短路跑呢?其实满足上诉两个条件下的最小生成树也有很多,因为题目的要求是最短路,所以我们只要在保证是最小生成树的条件下跑最短路那就是答案了。


为了满足一个联通块不能访问两次,我们考虑用状态压缩来记录状态解决。但是因为最多能分成70个联通块,那么就得用2^70得数组取记录状态。显然爆空间+超时。

这里有一个比较难想的优化:小于等于3个点的联通块是不会被访问两次的,为什么?这是因为Dijkstra会优先选择最短路,而小于等于3个点的联通块中的任两个点的距离都是短边,所以这种联通块内部有未访问的临近结点应该会优先访问,一旦Dijkstra离开了这个联通块,那么就不可能回来了,而大于等于4个点的联通块如果不加限制的话跑Dijkstra其实离开了有可能再次跑回来,但这是不满足上诉两个条件的,必须得用状态记录加以限制。

所以现在联通块数量降到了70/4=17个,可以结束。那么用d[S][i]代表当前访问完成的联通块状态为S,现在在结点i的最短路,在上诉两个条件下跑一次最短路即可。答案就是所有情况下经过i点的最小的值。


细节详见代码:

#include<bits/stdc++.h>
#define mp(x,y) make_pair(x,y)
using namespace std;
typedef pair<int,pair<int,int>> piii;
const int N=;
int n,m,a,b,cnt,Newid,Size[N],id[N],nid[N],ans[N];
struct edge{
int x,y,z;
bool operator < (const edge &rhs) const {
return z<rhs.z;
}
}e[N<<]; int tot=,head[N],to[N<<],nxt[N<<],len[N<<];
void add_edge(int x,int y,int z) {
nxt[++tot]=head[x]; to[tot]=y; len[tot]=z; head[x]=tot;
} int fa[N];
int getfa(int x) { return x==fa[x] ? x : fa[x]=getfa(fa[x]); } void Krusual() {
for (int i=;i<=n;i++) fa[i]=i;
for (int i=;i<=m;i++) {
int x=getfa(e[i].x),y=getfa(e[i].y);
if (e[i].z==b || x==y) continue;
fa[y]=fa[x];
}
} priority_queue<piii> q;
int dis[<<][]; bool vis[<<][];
void Dijkstra() {
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
q.push(mp(,mp(,)));
dis[][]=;
while (!q.empty()) {
int now=-q.top().first; pair<int,int> u=q.top().second; q.pop();
ans[u.second]=min(ans[u.second],now);
if (vis[u.first][u.second]) continue;
vis[u.first][u.second]=;
for (int i=head[u.second];i;i=nxt[i]) {
int v=to[i];
if (id[v]==id[u.second] && len[i]==b) continue; //条件一:不能在内部走长边
if (nid[v] && (u.first&(<<nid[v]))) continue; //条件二:不能往回走 int S=u.first;
if (nid[u.second] && nid[v]!=nid[u.second]) S|=(<<nid[u.second]); if (dis[u.first][u.second]+len[i]<dis[S][v]) {
dis[S][v]=dis[u.first][u.second]+len[i];
q.push(mp(-dis[S][v],mp(S,v)));
}
}
}
} int main()
{
cin>>n>>m>>a>>b;
for (int i=;i<=m;i++) {
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
add_edge(e[i].x,e[i].y,e[i].z);
add_edge(e[i].y,e[i].x,e[i].z);
}
sort(e+,e+m+);
Krusual(); for (int i=;i<=n;i++) {
Size[getfa(i)]++;
if (fa[i]==i) id[i]=++cnt;
}
for (int i=;i<=n;i++) id[i]=id[getfa(i)];
for (int i=;i<=n;i++)
if (Size[i]>=) nid[i]=++Newid;
for (int i=;i<=n;i++) nid[i]=nid[getfa(i)]; memset(ans,0x3f,sizeof(ans));
Dijkstra(); for (int i=;i<=n;i++) printf("%d ",ans[i]);
return ;
}

Codeforces Round #556 CF1149D Abandoning Roads的更多相关文章

  1. Codeforces Round #556 题解

    Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...

  2. Codeforces Round #556 (Div. 1)

    Codeforces Round #556 (Div. 1) A. Prefix Sum Primes 给你一堆1,2,你可以任意排序,要求你输出的数列的前缀和中质数个数最大. 发现只有\(2\)是偶 ...

  3. Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...

  4. Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Descripti ...

  5. Codeforces Round #556 (Div. 2)

    比赛链接 A 贪心 #include <cstdlib> #include <cstdio> #include <algorithm> #include <c ...

  6. Codeforces Round #556 (Div. 2) D. Three Religions 题解 动态规划

    题目链接:http://codeforces.com/contest/1150/problem/D 题目大意: 你有一个参考串 s 和三个装载字符串的容器 vec[0..2] ,然后还有 q 次操作, ...

  7. Codeforces Round #556 (Div. 2)-ABC(这次的题前三题真心水)

    A. Stock Arbitraging 直接上代码: #include<cstdio> #include<cstring> #include<iostream> ...

  8. CF1149D Abandoning Roads(图论,最短路,状态压缩,最小生成树)

    题目大意:$n$ 个点,$m$ 条边的无向图,边权只有两种,小的为 $a$,大的为 $b$. 对于每个点 $p$,询问在这张图所有的最小生成树上,$1$ 到 $p$ 的最短距离的最小值. $2\le ...

  9. Codeforces Round #556(Div.1)

    A 容易发现i,i+1至少有一个数出现,于是可以让尽量多的2和奇数出现 #include<bits/stdc++.h> using namespace std; int n,s1,s2; ...

随机推荐

  1. elasticsearch relevance score相关性评分的计算

    一.多shard场景下relevance score不准确问题 1.问题描述: 多个shard下,如果每个shard包含指定搜索条件的document数量不均匀的情况下,会导致在某个shard上doc ...

  2. linux随笔-01

    认识linux 开源共享精神 低风险 高品质 低成本 更透明 开源软件的特点 使用自由.修改自由.传播自由.收费自由以及创建衍生品的自由 常见的开源许可协议 GNU GPL(GNU General P ...

  3. jQuery HTML-删除元素

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  4. CDN(Content Delivery Network)内容分发网络

    CDN的全称是Content Delivery Network,即内容分发网络.其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快.更稳定.通过在网络各处放置节 ...

  5. AcWing 225. 矩阵幂求和 (矩阵快速幂+分治)打卡

    题目:https://www.acwing.com/problem/content/227/ 题意:给你n,k,m,然后输入一个n阶矩阵A,让你求  S=A+A^2+A^3.+......+A^k 思 ...

  6. dedecms SESSION变量覆盖导致SQL注入漏洞修补方案

    dedecms的/plus/advancedsearch.php中,直接从$_SESSION[$sqlhash]获取值作为$query带入SQL查询,这个漏洞的利用前提是session.auto_st ...

  7. [CSP-S模拟测试]:抽卡(概率DP)

    题目描述 水上由岐最近在肝手游,游戏里有一个氪金抽卡的活动.有$n$种卡,每种卡有 3 种颜色.每次抽卡可能什么也抽不到,也可能抽到一张卡.每氪金一次可以连抽 m 次卡,其中前$m−1$次抽到第$i$ ...

  8. JS-MiniUI:百科

    ylbtech-JS-MiniUI:百科 MINIUI是一款优秀的JS前端web框架,提供丰富.强大控件库,能快速开发企业级Web应用软件.该软件以美观精致的界面和快速的页面响应速度获得用户的好评.是 ...

  9. jsp+js完成用户一定时间未操作就跳到登录页面

    <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" ...

  10. Java学习之面向对象---继承

    继承:子继承父,子可以拥有父的所有. 继承的好处: 1.提高了代码的复用性 2.让类与类之间产生了关系.有了这个关系,才有了多态的特性 Java 只支持单继承,不支持多继承 class A { voi ...