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个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...
随机推荐
- OpenCV installation on Linux
Getting the Cutting-edge OpenCV from the Git Repository Launch Git client and clone OpenCV repositor ...
- 《FLASH CC 2015 CANVAS 中文教程》——2、基本的交互(点击、触摸)事件
注::如果你对 FLASH 这个软件操作不够熟悉,建议你可以先看看FLASH动画之类的书. :FLASH CC 在文中直接简称为CC. :以下所以文章中所说的快捷键 如果你按了不起作用,请检查是否有其 ...
- jQuery的.click,.bind,.unbind,.on,.off,.delegate,.undelegate
.click与.bind .click和.bind都是给每个元素绑定事件,对于只绑定一个click事件,.bind事件的简写就是.click那种方式. 这两种方式都会出现两个问题: 第一个问题,如果要 ...
- Win7路由器设置过程
随着应用win7系统的人越来越多,对于这个系统的应用就更多了,其中大家最关注的就是这个系统和路由器上网的问题.下面,我们就来讲解一下win7系统的路由器的设置过程. 首先打开浏览器,在地址栏输入192 ...
- struts2 传递数组、List、Map
struts2 传递数组.List.Map jsp文件 数组: <s:textfield name="ages" value="a1">&l ...
- c trans
#define BUFSIZE 100 char buf[BUFSIZE]; ; int getch(void) { )? buf[--bufp] : getchar(); } void ungetc ...
- JavaSE复习_7 异常
△子父类涉及的异常问题: 1.子类在覆盖方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类,且只能抛出异常的子集 2.如果父类抛出了多个异常,子类只 ...
- 【Todo】pthread_key_t 和 pthread_once_t学习
这两个函数应该都是和线程局部变量有关的.有时间学习一下. 可以参考如下文章: <Linux线程私有数据pthread_key_t> <posix多线程有感--线程高级编程(pthre ...
- maven编译项目时提示:cached in the local repository
今天使用命令mvn compile编译maven项目时提示错误信息,部分错误信息如下: ...... was cached in the local repository, resolution wi ...
- 转:C语言中的static变量和C++静态数据成员(static member)
转自:C语言中的static变量和C++静态数据成员(static member) C语言中static的变量:1).static局部变量 a.静态局部变量在函数内定义,生存期为整个程序 ...