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 最小生成树的更多相关文章

  1. [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)

    1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 802  Solved: 344[Submit][Sta ...

  2. 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树

    这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. ...

  3. BZOJ1937 [Shoi2004]Mst 最小生成树

    首先由贪心的想法知道,树边只减不加,非树边只加不减,令$w_i$表示i号边原来的边权,$d_i$表示i号边的改变量 对于一条非树边$j$连接着两个点$x$.$y$,则对于$xy$这条路径上的所有树边$ ...

  4. 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)

    [BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...

  5. BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]

    传送门 题意: 给一张无向图和一棵生成树,改变一些边的权值使生成树为最小生成树,代价为改变权值和的绝对值,求最小代价 线性规划的形式: $Min\quad \sum\limits_{i=1}^{m} ...

  6. [BZOJ 1937][Shoi2004]Mst 最小生成树

    传送门 $ \color{red} {solution:} $ 对于每条树边\(i\),其边权只可能变小,对于非树边\(j\),其边权只可能变大,所以对于任意非树边覆盖的树边有 \(wi - di & ...

  7. MST最小生成树

    首先,贴上一个很好的讲解贴: http://www.wutianqi.com/?p=3012 HDOJ 1233 还是畅通工程 http://acm.hdu.edu.cn/showproblem.ph ...

  8. [poj1679]The Unique MST(最小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28207   Accepted: 10073 ...

  9. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

随机推荐

  1. trampoline蹦床函数解决递归调用栈问题

    递归函数的调用栈太多,造成溢出,那么只要减少调用栈,就不会溢出.怎么做可以减少调用栈呢?就是采用"循环"换掉"递归". 下面是一个正常的递归函数. functi ...

  2. 如何快速搭建yum源

    yum命令能够从指定的服务器自动下载rpm包并安装,它最强大的地方就是可以自动处理软件包的依赖关系,能够一次安装所有依赖的关系包.下面将通过虚拟机平台介绍两种快速搭建yum源的方法: 一.有网络的情况 ...

  3. 打包应用和构建Docker镜像(docker在windows上)

    在构建Docker时编译应用 一般有两种方法在构建镜像时进行打包应用.第一种方法就是使用基本的镜像,该镜像包括应用平台和构建工具,因此在Dockerfile中,复制源代码到镜像中并在构建镜像时编译ap ...

  4. CsvReader和CsvWriter操作csv文件

    使用方法: 提供把实例数据输出到磁盘csv文件的功能 提供读取csv文件,并封装成指定实例的功能 小工具自己依赖了slf4j+logbak,以及fastJson,如果与系统冲突,可以在pom文件中去除 ...

  5. 局域网arpspoof欺骗获取cookie/图片/密码

    开启路由转发功能 查看IP转发功能是否打开 默认是不开起,0,我这里是修改后的,显示1. 修改转发功能,1为允许. 修改成功后再进行Arpspoof欺骗 如果开始劫持后,自己电脑无法联网了 ??? 检 ...

  6. 配置Tomcat使用HTTP/2

    转自: https://zhuanlan.zhihu.com/p/21349186 前情提要: Tomcat高效响应的秘密(一) Sendfile与Gzip Tomcat高效响应的秘密(二) keep ...

  7. Java-URLEncoder.encode 什么时候才是必须的

    当你希望把一段 URL 当成另一个 URL 的参数时,比如:当用户点击交易的按钮时你发现未登录就跳转到 login 页面同时带上一个参数记录在登录之前用户是希望访问的那个交易页面,这样在登录完成之后再 ...

  8. 团队作业 week9

    1. Bug bash 我们现在在TFS服务器中有17个BUG等待分配,但是所有BUG的数量肯定不止. 2. Scenario testing 测试人员以不同的身份来对网站进行测试,对于无法满足当前身 ...

  9. 《 Spring1之第二次站立会议(重发)》

    < 第二次站立会议(重发)> 昨天,我把找到的代码和协议资料等相关资料在团队里做了相应的汇报: 今天,我对自己找到的代码进行了相关的了解后,把它们在编译环境中进行了编译以及接着对代码进行逐 ...

  10. 项目Beta冲刺(团队)随笔集

    凡事预则立 项目Beta冲刺准备 第一天 项目Beta冲刺(团队)第一天 第二天 项目Beta冲刺(团队)第二天 第三天 项目Beta冲刺(团队)第三天 第四天 项目Beta冲刺(团队)第四天 第五天 ...