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

Description

Input

第一行为N、M,其中 表示顶点的数目, 表示边的数目。顶点的编号为1、2、3、……、N-1、N。接下来的M行,每行三个整数Ui,Vi,Wi,表示顶点Ui与Vi之间有一条边,其权值为Wi。所有的边在输入中会且仅会出现一次。再接着N-1行,每行两个整数Xi、Yi,表示顶点Xi与Yi之间的边是T的一条边。

Output

输出最小权值

Sample Input

6 9
1 2 2
1 3 2
2 3 3
3 4 3
1 5 1
2 6 3
4 5 4
4 6 7
5 6 6
1 3
2 3
3 4
4 5
4 6

Sample Output

8
【样例说明】
边(4,6)的权由7修改为3,代价为4
边(1,2)的权由2修改为3,代价为1
边(1,5)的权由1修改为4,代价为3
所以总代价为4+1+3=8
修改方案不唯一。

HINT

1<=n<=50,1<=m<=800,1<=wi<=1000
n-->点数..m-->边数..wi--->边权

题解:神题~

显然,树边的权值一定减小,非树边的权值一定增大,所以如果非树边j覆盖了树边i,则有wj+dj>=wi-di,即di+dj>=wi-wj。所以这。。。tm是KM算法中的顶标?

复习KM的原理,KM算法就是始终满足:对于每条边a-b,l(a)+l(b)>=v(a,b),并且所有l(a)+l(b)=v(a,b)的边构成的子图叫相等子图。并在满足上述条件下不断调整定标,使得相等子图不断扩大。

而对于本题,让wi-wj就是边权,然后求出最优匹配既是答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,Cnt,nm,ans;
int map[60][60],pa[810],pb[810],pc[810],To[110],Next[110],Val[110],Head[60],len[60];
int fa[60],dep[60],bel[60],la[60],lb[810],va[60],vb[810],from[810],v[60][810];
inline void Add(int a,int b,int c)
{
To[Cnt]=b,Val[Cnt]=c,Next[Cnt]=Head[a],Head[a]=Cnt++;
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void Dfs(int x)
{
for(int i=Head[x];i!=-1;i=Next[i]) if(To[i]!=fa[x]) fa[To[i]]=x,dep[To[i]]=dep[x]+1,bel[To[i]]=Val[i],Dfs(To[i]);
}
void build(int a,int b,int c)
{
if(dep[a]<dep[b]) swap(a,b);
while(dep[a]>dep[b]) v[bel[a]][nm]=max(0,len[bel[a]]-c),a=fa[a];
while(a!=b) v[bel[a]][nm]=max(0,len[bel[a]]-c),v[bel[b]][nm]=max(0,len[bel[b]]-c),a=fa[a],b=fa[b];
}
int dfs(int x)
{
va[x]=1;
for(int y=1;y<=nm;y++) if(!vb[y]&&la[x]+lb[y]==v[x][y])
{
vb[y]=1;
if(!from[y]||dfs(from[y]))
{
from[y]=x;
return 1;
}
}
return 0;
}
int main()
{
n=rd(),m=rd();
int i,j,k,a,b;
memset(Head,-1,sizeof(Head));
for(i=1;i<=m;i++) pa[i]=rd(),pb[i]=rd(),pc[i]=rd(),map[pa[i]][pb[i]]=map[pb[i]][pa[i]]=i;
for(i=1;i<n;i++)
{
a=rd(),b=rd(),Add(a,b,i),Add(b,a,i),len[i]=pc[map[a][b]],map[a][b]=map[b][a]=0;
}
dep[1]=1,Dfs(1);
for(i=1;i<=m;i++) if(map[pa[i]][pb[i]])
{
nm++;
build(pa[i],pb[i],pc[i]);
}
for(i=1;i<=n;i++) for(j=1;j<=nm;j++) la[i]=max(la[i],v[i][j]);
for(i=1;i<=n;i++)
{
while(1)
{
memset(va,0,sizeof(va)),memset(vb,0,sizeof(vb));
if(dfs(i)) break;
int tmp=1<<30;
for(j=1;j<=n;j++) if(va[j]) for(k=1;k<=nm;k++) if(!vb[k]) tmp=min(tmp,la[j]+lb[k]-v[j][k]);
if(tmp==1<<30) break;
for(j=1;j<=n;j++) if(va[j]) la[j]-=tmp;
for(j=1;j<=nm;j++) if(vb[j]) lb[j]+=tmp;
}
}
for(i=1;i<=n;i++) ans+=la[i];
for(i=1;i<=nm;i++) ans+=lb[i];
printf("%d",ans);
return 0;
}

【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)的更多相关文章

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

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

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

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

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

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

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

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

  5. 【bzoj1937】 Shoi2004—Mst 最小生成树

    http://www.lydsy.com/JudgeOnline/problem.php?id=1937 (题目链接) 题意 一个无向图,给出一个生成树,可以修改每条边的权值,问最小修改多少权值使得给 ...

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

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

  7. MST(最小生成树)——Prim算法——HDU 1879-继续畅通工程

    Prim算法很好理解,特别是学完了迪杰斯特拉算法之后,更加能理解Prim的算法思想 和迪杰斯特拉算法差不多,由于最后要形成连通图,故任意指定一个点,作为初始点,遍历所有点,以当前最小权值的点(和迪杰斯 ...

  8. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

  9. 图论算法(五)最小生成树Prim算法

    最小生成树\(Prim\)算法 我们通常求最小生成树有两种常见的算法--\(Prim\)和\(Kruskal\)算法,今天先总结最小生成树概念和比较简单的\(Prim\)算法 Part 1:最小生成树 ...

随机推荐

  1. docker入门——镜像简介

    什么是docker镜像 Docker镜像是由文件系统叠加而成. 最底端是一个引导文件系统,即bootfs: 这很像典型的Linux/Unix的引导文件系统.Docker用户几乎永远不会和引导文件系统有 ...

  2. REDIS 内存满时删除策略

    REDIS 内存满时删除策略

  3. TP框架中模糊查询实现

    TP框架中模糊查询实现 $where['g.name'] = array('like','%'.$groupname.'%'); 表达式查询 上面的查询条件仅仅是一个简单的相等判断,可以使用查询表达式 ...

  4. spring-boot-redis-cluster简单整合例子

    代码地址如下:http://www.demodashi.com/demo/13184.html 一.前言 spring-boot项目整合redis很常见,Redis 一般上生产的时候都是以集群模式部署 ...

  5. freemarker相关

    大部分引入:http://www.blogjava.net/alinglau36/archive/2011/02/23/344970.html Freemarker操作字符串 1.substring( ...

  6. curl 重定向问题

    今天在curl一个网站的时候遇到一个奇怪的问题,下面是输出: lxg@lxg-X240:~$ curl -L http://www.yngs.gov.cn/ -v * Hostname was NOT ...

  7. Redis之SkipList数据结构

    0.前言 Redis中有序集合zset需要使用skiplist作为存储数据结构, 关于skiplist数据结构描述可以查询wiki, 本文主要介绍Redis实现的skiplist的细节. 1.数据结构 ...

  8. Atitit.嵌入式web 服务器 java android最佳实践

    Atitit.嵌入式web 服务器 java android最佳实践 1. Android4.4.21 2. 自己的webserver1 3. CyberHTTP for Java  cybergar ...

  9. atitit.guice3 绑定方式打总结生成非单例对象toInstance toProvider区别 v2 pb29

    atitit.guice3 绑定方式打总结生成非单例对象toInstance toProvider区别 v2 pb29 1. 三 绑定方式的介绍1 2. To接口,链式绑定,用的最多的1 3. toC ...

  10. WCF信道工厂Channel Factory

    ChannelFactory<TChannel> 类 一个创建不同类型通道的工厂,客户端使用这些通道将消息发送到不同配置的服务终结点. 命名空间: System.ServiceModel ...