【bzoj1937】 Shoi2004—Mst 最小生成树
http://www.lydsy.com/JudgeOnline/problem.php?id=1937 (题目链接)
题意
一个无向图,给出一个生成树,可以修改每条边的权值,问最小修改多少权值使得给出的生成树是最小生成树。
Solution
好神!!!!!
首先,由贪心可知,生成树上的边我们肯定是减小它的权值,非树边我们肯定是增大它的权值。假设树边$i$的权值$w_i$,修改后的权值$w_i-d_i$;非树边$j$的权值$w_j$,修改后的权值$w_j+d_j$。如果$j$有可能代替$i$,那么它们必须满足式子$w_i-d_i<=w_j+d_j$,移下项$w_i-w_j<=d_i+d_j$,是不是很像KM里面的顶标,所以我们把边当做点,边权为两个有制约关系的边的权值差,跑KM求最大权完美匹配就可以了。
纠结了好久,蛋疼死了。我们的确是要求最小的$\sum d_i$,但是$w_i-w_j<=d_i+d_j$的意义是要求对所有的$i,j$都得满足。我们需要在满足条件的情况下不断缩小$\sum d_i$,所以完美匹配以后我们可以使$\sum d_i$最小。
细节
边权非负。可能不会完美匹配,需要加点加边。
代码
// bzoj1937
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define MOD 1000000007
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=1010;
int head[maxn],deep[maxn],vis[maxn],fa[maxn],id[maxn][maxn],n,m,cnt;
int slack[maxn],vx[maxn],vy[maxn],lx[maxn],ly[maxn],p[maxn],mp[maxn][maxn];
struct data {int u,v,w;}a[maxn];
struct edge {int to,next;}e[maxn<<1]; void link(int u,int v) {
e[++cnt]=(edge){v,head[u]};head[u]=cnt;
e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void dfs(int x) {
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x]) {
deep[e[i].to]=deep[x]+1;
fa[e[i].to]=x;
dfs(e[i].to);
}
}
bool match(int x) {
vx[x]=cnt;
for (int y=1;y<=m;y++) if (vy[y]!=cnt) {
int t=lx[x]+ly[y]-mp[x][y];
if (!t) {
vy[y]=cnt;
if (!p[y] || match(p[y])) {p[y]=x;return 1;}
}
else slack[y]=min(slack[y],t);
}
return 0;
}
int KM() {
for (int i=1;i<=m;i++) {
lx[i]=-inf;
for (int j=1;j<=m;j++) lx[i]=max(lx[i],mp[i][j]);
}
cnt=0;
for (int x=1;x<=m;x++) {
for (int i=1;i<=m;i++) slack[i]=inf;
while (1) {
int d=inf;cnt++;
if (match(x)) break;
for (int i=1;i<=m;i++) if (vy[i]!=cnt) d=min(d,slack[i]);
for (int i=1;i<=m;i++) {
if (vx[i]==cnt) lx[i]-=d;
if (vy[i]==cnt) ly[i]+=d;
}
}
}
int ans=0;
for (int i=1;i<=m;i++) ans+=mp[p[i]][i];
return ans;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
id[a[i].u][a[i].v]=id[a[i].v][a[i].u]=i;
}
for (int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
link(u,v);vis[id[u][v]]=1;
}
dfs(1);memset(head,0,sizeof(head));cnt=0;
for (int i=1;i<=m;i++) if (!vis[i]) {
int x=a[i].u,y=a[i].v,w=a[i].w;
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
while (t--) mp[id[x][fa[x]]][i]=max(0,a[id[x][fa[x]]].w-w),x=fa[x];
while (x!=y) {
mp[id[x][fa[x]]][i]=max(0,a[id[x][fa[x]]].w-w);
mp[id[y][fa[y]]][i]=max(0,a[id[y][fa[y]]].w-w);
x=fa[x],y=fa[y];
}
}
printf("%d",KM());
return 0;
}
【bzoj1937】 Shoi2004—Mst 最小生成树的更多相关文章
- [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)
1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 802 Solved: 344[Submit][Sta ...
- 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树
这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. ...
- BZOJ1937 [Shoi2004]Mst 最小生成树
首先由贪心的想法知道,树边只减不加,非树边只加不减,令$w_i$表示i号边原来的边权,$d_i$表示i号边的改变量 对于一条非树边$j$连接着两个点$x$.$y$,则对于$xy$这条路径上的所有树边$ ...
- 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)
[BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...
- BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]
传送门 题意: 给一张无向图和一棵生成树,改变一些边的权值使生成树为最小生成树,代价为改变权值和的绝对值,求最小代价 线性规划的形式: $Min\quad \sum\limits_{i=1}^{m} ...
- [BZOJ 1937][Shoi2004]Mst 最小生成树
传送门 $ \color{red} {solution:} $ 对于每条树边\(i\),其边权只可能变小,对于非树边\(j\),其边权只可能变大,所以对于任意非树边覆盖的树边有 \(wi - di & ...
- MST最小生成树
首先,贴上一个很好的讲解贴: http://www.wutianqi.com/?p=3012 HDOJ 1233 还是畅通工程 http://acm.hdu.edu.cn/showproblem.ph ...
- [poj1679]The Unique MST(最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28207 Accepted: 10073 ...
- UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)
题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...
随机推荐
- jmeter阶梯加压线程组
添加阶梯加压线程组路径为鼠标捕获测试计划后,点击鼠标右键->添加->Threads(Users)->jp@gc – Stepping Thread Group(deprecated) ...
- c++三大概念要分清--重载,隐藏(重定义),覆盖(重写)
重载,隐藏(重定义),覆盖(重写)—这几个名词看着好像很像,不过其实一样都不一样!! 综述: 说明:覆盖中的访问修饰符可以不同是指可以不用显示地用virtual:当访问修饰符改为const或者stat ...
- golang应用打包成docker镜像
golang编译的应用是不需要依赖其他运行环境的,那么为什么还需要打包成docker镜像呢?当需要附带配置和日志等文件时可以更方便的移植和运行,下面介绍从dockerfile编译成镜像. 在项目根目录 ...
- swap分区和内存
1 查看swap 空间大小(总计): # free -m 默认单位为k, -m 单位为M total used fr ...
- AES128加密算法完整实现
概述 原本想把自己AES加密算法的整个实现过程给详细复述下来,分享给想学习的同学,也方便自己复习,但后来发现该工作量太大,加上作业太多没有过多的时间去写.所以就想把自己在学习的过程中多遇到的好的文章进 ...
- Python文本文件的输入输出操作学习
Python具有基本的文本文件读写功能.Python的标准库提供有更丰富的读写功能. 文本文件的读写主要通过open()所构建的文件对象来实现. 创建文件对象 我们打开一个文件,并使用一个对象来表示该 ...
- Rotation and Transform
A transformation matrix describes the rotation of a coordinate system while an object remains fixed. ...
- Python之并发编程-多进程
目录 一.multiprocessiong模块介绍 二.Process类的介绍 三.进一步介绍(守护进程.锁.队列.管道.事件等) 1.守护进程 2.锁(同步锁.互斥锁) 3.信号量(了解) 4.队列 ...
- django_models_Meta字段详解
Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.而可用的选项大致包含以下几类 abstract 这个属性是定义当前的模型是不是一个抽象类.所谓抽象类是不会对应数据 ...
- 为什么要读这本书《java编程思想》
在学校学习编程语言只是浅显的了解,不理解的的东西有很多 ,想通过这本书对java语言有更深的理解,对于以后的学习和工作会有很大的好处.与其了了草草的看你一些书,知其然而不知其所以然,这不是我想要的学习 ...