这道题拖了好久因为懒,结果1A了,惊讶∑( 口 ||

【题目大意】

给定一张n个顶点m条边的有权无向图。现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值。求最小代价之和。

【思路】

思路有点神,并不是我这种蒟蒻能够想到的XD

显然由贪心,树边必定变成wi-di,非树边必定变成wi+di (di≥0)

为了满足Mst的性质,考察一条非树边j,它加最小生成树后,必定构成一个环。对于环上的每一条树边i,有wi-di≤wj+dj,即di+dj≥wi-wj。这非常类似于KM的形式x[i]+y[i]≥wt[i][j]。

那么我们就如下操作:对于最小生成树,先预处理出所有节点的深度。对于一条非树边E(u,v),求出lca(u,v)。对于u->lca,lca->v上的每一条树边,由树边向非树边连一条(w树边-w非树边)的边。然后跑KM。

注意这个值可能小于0,由于变化量的绝对值之和必定大于0,我们就取为0即可。

【错误点】

lca和KM都写挂了一发orz

LCA的时候忘记了swim后,若u==v,返回u。

KM取slack的时候是取min的。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int MAXN=;
const int MAXM=+;
const int INF=0x7fffffff;
struct Edge
{
int u,v,w,t;
}edge[MAXM];
vector<int> E[MAXN];
int val[MAXM][MAXM];
int dep[MAXN],anc[MAXN][],faedge[MAXN];
int cnt,m,n; /**build tree**/
void addedge(int u,int v,int w)
{
edge[++cnt]=(Edge){u,v,w,};
E[u].push_back(cnt);
E[v].push_back(cnt);
} void dfs(int rt,int fa,int id)
{
dep[rt]=dep[fa]+;
anc[rt][]=fa;
faedge[rt]=id;
for (int i=;i<E[rt].size();i++)
{
int now=E[rt][i];
if (edge[now].t && edge[now].u!=fa && edge[now].v!=fa)
{
if (edge[now].u==rt) dfs(edge[now].v,rt,now);
else dfs(edge[now].u,rt,now);
}
}
} /*lca*/
int getanc()
{
for (int i=;i<;i++)
for (int j=;j<=n;j++)
anc[j][i]=anc[anc[j][i-]][i-];
} int swim(int u,int H)
{
int i=;
while (H>)
{
if (H&) u=u[anc][i];
H>>=;
i++;
}
return u;
} int LCA(int u,int v)
{
if (dep[u]<dep[v]) swap(u,v);
if (dep[u]!=dep[v]) u=swim(u,dep[u]-dep[v]);
if (u==v) return u;//不要忘了这句语句
for (int i=;i>=;i--)
{
if (anc[u][i]!=anc[v][i])
{
u=anc[u][i];
v=anc[v][i];
}
}
return anc[u][];
} /*KM*/ void Addedge(int u,int v,int w)
{
val[u][v]=max(w,);//由于两条边的变化量的绝对值之和不可能为负数,则必定设为0 ☆☆☆☆☆☆
} void build(int a,int b,int id)
{
if (dep[a]<dep[b]) swap(a,b);
while (a!=b)
{
Addedge(faedge[a],id,edge[faedge[a]].w-edge[id].w);
a=anc[a][];
}
} int fx[MAXM],fy[MAXM],visx[MAXM],visy[MAXM],slack[MAXM],lk[MAXM]; int Hungary_dfs(int u)
{
visx[u]=;
for (int i=;i<=m;i++)
{
int wt=fx[u]+fy[i]-val[u][i];
if (!visy[i] && wt==)
{
visy[i]=;
if (lk[i]==- || Hungary_dfs(lk[i]))
{
lk[i]=u;
return ;
}
}
else slack[i]=min(slack[i],wt);//注意这里是取较小值不是较大
}
return ;
} void KM()
{
memset(lk,-,sizeof(lk));
for (int i=;i<=m;i++)
{
fx[i]=-INF;
fy[i]=;
for (int j=;j<=m;j++) fx[i]=max(fx[i],val[i][j]);
}
for (int i=;i<=m;i++)
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
memset(slack,0x3f,sizeof(slack));
while (!Hungary_dfs(i))
{
int delta=INF;
for (int j=;j<=m;j++)
if (!visy[j]) delta=min(delta,slack[j]);
for (int j=;j<=m;j++)
{
if (visx[j])
{
fx[j]-=delta;
visx[j]=;
}
if (visy[j])
{
fy[j]+=delta;
visy[j]=;
}
}
}
}
int ans=;
for (int i=;i<=m;i++) ans+=(fx[i]+fy[i]);
printf("%d",ans);
} /**main part**/
void init()
{
cnt=;
scanf("%d%d",&n,&m);
for (int i=;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
} for (int i=;i<=(n-);i++)
{
int x,y;
scanf("%d%d",&x,&y);
for (int j=;j<E[x].size();j++)
{
int id=E[x][j];
if ((edge[id].u==x && edge[id].v==y)||(edge[id].v==x && edge[id].u==y))
{
edge[id].t=;
break;
}
}
}
dfs(,,);//建立以1为根的树,方便后续lca操作。注意仅有树边加入,非树边不加入
} void solve()
{
memset(val,,sizeof(val));
getanc();
for (int i=;i<=m;i++)
{
if (!edge[i].t)
{
int lca=LCA(edge[i].u,edge[i].v);
build(edge[i].u,lca,i);
build(edge[i].v,lca,i);
}
}
KM();
} int main()
{
init();
solve();
return ;
}

【KM】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. BZOJ1937 [Shoi2004]Mst 最小生成树

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

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

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

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

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

  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. 用ajax、PHP、session做购物车

    购物车网页代码 1.登录界面login.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...

  2. wampserver 虚拟主机

    转载:http://blog.csdn.net/knight_quan/article/details/51830683 1.背景: 在进行网站开发的时候,通常需要以http://localhost或 ...

  3. Java生成验证码简记

    验证码定义 验证码(captcha):是一种区分用户是计算机还是人的公共全自动程序. 作用:可以防止恶意破解密码.刷票.灌水,有效防止对某一个特定注册用户用特定程序进行暴力破解的登录尝试. 验证码交互 ...

  4. SDUT 3917

    UMR 现在手里有 n 张康纳的表情,最上面一张是玛吉呀巴库乃.现在 UMR 如果每次把最上面的 m 张牌移到最下面而不改变他们的顺序及朝向,那么至少经过多少次移动玛吉呀巴库乃才会又出现在最上面呢? ...

  5. CF 900B

    CF 900B Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u   Descript ...

  6. 【洛谷 P3191】 [HNOI2007]紧急疏散EVACUATE(二分答案,最大流)

    题目链接 sb错误调了3hour+.. bfs预处理出每个\(.\)到每个\(D\)的最短距离. 二分时间\(t\),把每个\(D\)拆成\(t\)个点,这\(t\)个点两两连边,流量\(INF\)表 ...

  7. 23、Xpath

    1.什么是Xpath?1.XPath即为XMLPath的简称,它是一种用来确定XML文档中某部分位置的语言.2.HTML可以看做是XML的一种实现,所以selenium用户可以使用这种强大的语言在we ...

  8. linux学习记录.1.安装

    最近想了想决定开始学习linux. 在百度了一番后开始了安装,虚拟机VirtualBox,ubuntu. 基于VirtualBox虚拟机安装Ubuntu图文教程: http://blog.csdn.n ...

  9. PHP代码审计学习

    原文:http://paper.tuisec.win/detail/1fa2683bd1ca79c 作者:June 这是一次分享准备.自己还没有总结这个的能力,这次就当个搬运工好了~~ 0x01 工具 ...

  10. 浅析linux内核中timer定时器的生成和sofirq软中断调用流程(转自http://blog.chinaunix.net/uid-20564848-id-73480.html)

    浅析linux内核中timer定时器的生成和sofirq软中断调用流程 mod_timer添加的定时器timer在内核的软中断中发生调用,__run_timers会spin_lock_irq(& ...