BZOJ1937 [Shoi2004]Mst 最小生成树
首先由贪心的想法知道,树边只减不加,非树边只加不减,令$w_i$表示i号边原来的边权,$d_i$表示i号边的改变量
对于一条非树边$j$连接着两个点$x$、$y$,则对于$xy$这条路径上的所有树边$i$,都要满足:$w_i - d_i \le w_j + d_j$
移项可得$w_i -w_j \le d_i + d_j$
于是我们发现$d[]$就是KM算法里的顶标了,直接跑最大匹配即可
/**************************************************************
Problem: 1937
User: rausen
Language: C++
Result: Accepted
Time:700 ms
Memory:4796 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
const int N = ;
const int M = ;
const int inf = 1e9; inline int read(); struct edge {
int next, to, id;
edge(int _n = , int _t = , int _i = ) : next(_n), to(_t), id(_i) {}
} e[N << ]; struct Edge {
int x, y, v, f; inline void get() {
x = read(), y = read(), v = read(), f = ;
}
} E[M]; struct tree_node {
int dep, fa[], e;
} tr[N]; int n, m;
int first[N], tot;
int mp[M][M]; namespace KM {
int slack[M], lx[M], ly[M], linky[M];
bool visx[M], visy[M]; bool find(int x) {
int y, tmp;
for (visx[x] = y = ; y <= m; ++y) if (!visy[y]) {
tmp = lx[x] + ly[y] - mp[x][y];
if (tmp == ) {
visy[y] = ;
if (linky[y] == - || find(linky[y])) {
linky[y] = x;
return ;
}
} else
if (slack[y] > tmp) slack[y] = tmp;
}
return ;
} int work() {
static int i, j, x, d, res;
memset(linky, -, sizeof(linky));
memset(ly, , sizeof(ly));
for (i = ; i <= m; ++i)
for (j = , lx[i] = -inf; j <= m; ++j)
lx[i] = max(lx[i], mp[i][j]);
for (x = ; x <= m; ++x) {
for (i = ; i <= m; ++i)
slack[i] = inf;
while() {
memset(visx, , sizeof(visx));
memset(visy, , sizeof(visy));
if (find(x)) break;
d = inf;
for (i = ; i <= m; ++i)
if (!visy[i]) d = min(d, slack[i]);
for (i = ; i <= m; ++i)
if (visx[i]) lx[i] -= d;
for (i = ; i <= m; ++i)
if (visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
for (res = , i = ; i <= m; ++i)
res += mp[linky[i]][i];
return res;
}
}; inline void Add_Edges(int x, int y, int id) {
e[++tot] = edge(first[x], y, id), first[x] = tot;
e[++tot] = edge(first[y], x, id), first[y] = tot;
} #define y e[x].to
inline void dfs(int p) {
int i, x;
tr[p].dep = tr[tr[p].fa[]].dep + ;
for (i = ; i <= ; ++i)
tr[p].fa[i] = tr[tr[p].fa[i - ]].fa[i - ];
for (x = first[p]; x; x = e[x].next)
if (y != tr[p].fa[]) {
tr[y].fa[] = p, tr[y].e = e[x].id;
dfs(y);
}
}
#undef y inline int lca(int x, int y) {
static int i;
if (tr[x].dep < tr[y].dep) swap(x, y);
for (i = ; ~i; --i)
if (tr[tr[x].fa[i]].dep >= tr[y].dep) x = tr[x].fa[i];
if (x == y) return x;
for (i = ; ~i; --i)
if (tr[x].fa[i] != tr[y].fa[i])
x = tr[x].fa[i], y = tr[y].fa[i];
return tr[x].fa[];
} inline void build(int x, int f, int e, int v) {
while (x != f)
mp[tr[x].e][e] = max(, E[tr[x].e].v - v), x = tr[x].fa[];
} int main() {
int i, j;
int x, y, f;
n = read(), m = read();
for (i = ; i <= m; ++i)
E[i].get();
for (i = ; i < n; ++i) {
x = read(), y = read();
for (j = ; j <= m; ++j)
if ((E[j].x == x && E[j].y == y) || (E[j].x == y && E[j].y == x)) {
E[j].f = ;
Add_Edges(x, y, j);
break;
}
}
dfs();
for (i = ; i <= m; ++i)
if (!E[i].f) {
x = E[i].x, y = E[i].y, f = lca(x, y);
build(x, f, i, E[i].v);
build(y, f, i, E[i].v);
}
printf("%d\n", KM::work());
return ;
} inline int read() {
static int x;
static char ch;
x = , ch = getchar();
while (ch < '' || '' < ch)
ch = getchar();
while ('' <= ch && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
}
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 最小生成树 KM算法(线性规划)
[BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...
- 【bzoj1937】 Shoi2004—Mst 最小生成树
http://www.lydsy.com/JudgeOnline/problem.php?id=1937 (题目链接) 题意 一个无向图,给出一个生成树,可以修改每条边的权值,问最小修改多少权值使得给 ...
- 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个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...
随机推荐
- iOS - KVC 键值编码
1.KVC KVC 是 Key-Value Coding 的简写,是键值编码的意思,属于 runtime 方法.Key Value Coding 是 cocoa 的一个标准组成部分,是间接给对象属性设 ...
- phpmailer发送邮件 SMTP Error: Could not authenticate 错误
这个错误说明虚拟主机不支持PHPMailer默认调用的fsockopen函数,找到class.smtp.php文件,搜索fsockopen,就找到了这样一段代码: $this->smtp_con ...
- thinkphp分页显示
先在Common\Comon里建一个function.php公共方法,然后在里面新建一个getpage方法,代码如下: <?php /** * TODO 基础分页的相同代码封装,使前台的代码更少 ...
- linux内核的熵池
也可以看百度科 Linux内核采用熵来描述数据的随机性.熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大.在信息学中,熵被用来表征一个符号或 ...
- HTML5Canvas标签
- 【Todo】蒙特卡洛(蒙特卡罗)树 & 卷积网络
https://www.zhihu.com/question/41176911/answer/90066752 这里面有关于Deep Learning和蒙特卡洛树的一些内容 https://www.z ...
- 详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法
详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法 一 编译链接 1 在相应官网下载jsoncpp 2 解压得到jsoncpp-src-0.5.0文件 3 打开jsoncpp-src- ...
- PO BO VO DTO POJO DAO 概念及其作用
PO BO VO DTO POJO DAO 概念及其作用(附转换图) 博客分类: java javadaovopojobo J2EE开发中大量的专业缩略语很是让人迷惑, 特别是对于刚毕业 ...
- Android开发面试经——3.常见Java基础笔试题
Android开发(29) 版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...
- CSS重置代码和常用公共代码
发的发生的发生法士大夫撒打发士大夫