传送门

不难发现,对于每一条树边肯定要减小它的权值,对于每一条非树边要增加它的权值

对于每一条非树边\(j\),他肯定与某些树边构成了一个环,那么它的边权必须大于等于这个环上的所有边

设其中一条边为\(i\),变化量为\(x\),那么就要满足\(w_i-x_i\leq w_j+x_j\),即\(x_i+x_j\geq w_i-w_j\)

然后它就是一个线性规划了,长这个样子

\[Min\sum_i x_i+\sum_jx_j
\]

\[x_i+x_j\geq w_i-w_j
\]

\[x_i\geq 0
\]

然后因为这玩意儿是求目标函数的最小值,所以我们得把它对偶之后变成求它的最大值,然后它长成了这个样子(令\(y_k\)为第\(k\)个约束条件对偶后的变量,\(d_{k,i}\)表示第\(k\)个约束中是否有\(x_i\)这个变量)

\[Max\sum (w_i-w_j)y_k
\]

\[\sum_k y_kx_{ki}\leq 1
\]

\[y_i\geq 0
\]

然后直接上单纯形

因为一些精度原因,如果最后的答案在\(-eps\)到\(eps\)之间手动输出\(0\)否则它的答案会是个负数……

  1. //minamoto
  2. #include<bits/stdc++.h>
  3. #define R register
  4. #define Loli true
  5. #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
  6. #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
  7. #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
  8. using namespace std;
  9. char buf[1<<21],*p1=buf,*p2=buf;
  10. inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
  11. int read(){
  12. R int res,f=1;R char ch;
  13. while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
  14. for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
  15. return res*f;
  16. }
  17. const int N=1005,M=10005;const double eps=1e-8,inf=1e18;
  18. struct eg{int v,nx,id;}e[N<<1];int head[N],tot;
  19. inline void add(R int u,R int v,R int id){e[++tot]={v,head[u],id},head[u]=tot;}
  20. int n,m,nn,mm,u,v,x,dep[N],fa[N],id[N],U[N],V[N],W[N],F[N],G[N][N];
  21. double a[N][M];
  22. void dfs(int u){go(u)if(v!=fa[u])fa[v]=u,id[v]=e[i].id,dep[v]=dep[u]+1,dfs(v);}
  23. void pivot(int l,int e){
  24. double t=a[l][e];a[l][e]=1;fp(i,0,m)a[l][i]/=t;
  25. fp(i,0,n)if(i!=l&&fabs(a[i][e])>eps){
  26. t=a[i][e],a[i][e]=0;
  27. fp(j,0,m)a[i][j]-=t*a[l][j];
  28. }
  29. }
  30. void simplex(){
  31. while(Loli){
  32. int l=0,e=0;double mn=inf;
  33. fp(i,1,m)if(a[0][i]>eps){e=i;break;}if(!e)return;
  34. fp(i,1,n)if(a[i][e]>eps&&a[i][0]/a[i][e]<mn)mn=a[i][0]/a[i][e],l=i;
  35. pivot(l,e);
  36. }
  37. }
  38. int main(){
  39. // freopen("testdata.in","r",stdin);
  40. nn=read(),mm=read();
  41. fp(i,1,mm)U[i]=read(),V[i]=read(),W[i]=read(),G[U[i]][V[i]]=G[V[i]][U[i]]=i;
  42. fp(i,1,nn-1)u=read(),v=read(),x=G[u][v],add(U[x],V[x],x),add(V[x],U[x],x);
  43. dfs(1),n=mm;
  44. fp(i,1,mm)if(F[i])a[i][0]=1;
  45. else{
  46. a[i][0]=1,u=U[i],v=V[i];
  47. while(u!=v){
  48. if(dep[u]<dep[v])swap(u,v);
  49. x=id[u];if(W[x]>W[i])++m,a[x][m]=a[i][m]=1,a[0][m]=W[x]-W[i];
  50. u=fa[u];
  51. }
  52. }simplex();if(a[0][0]<eps&&a[0][0]>-eps)puts("0");
  53. else printf("%.0lf\n",-a[0][0]);return 0;
  54. }

P4412 [SHOI2004]最小生成树的更多相关文章

  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 最小生成树 KM算法(线性规划)

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

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

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

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

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

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

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

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

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

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

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

  8. 最小生成树(Kruskal算法-边集数组)

    以此图为例: package com.datastruct; import java.util.Scanner; public class TestKruskal { private static c ...

  9. 最小生成树计数 bzoj 1016

    最小生成树计数 (1s 128M) award [问题描述] 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一 ...

随机推荐

  1. HDU 5700 区间交

    枚举起点 二分终点 树状数组check #include<iostream> #include<cstring> #include<cmath> #include& ...

  2. HDU 1024 【DP】

    题意: 给n个数将其分成连续的m组,使得这些组的数加和最大,组与组之间可以空数. /* dp[i][j]表示将前j个数分成i个组最大值 状态转移方程是: dp[i][j]=max(dp[i-1][0. ...

  3. [Lydsy1706月赛]大根堆

    4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 358  Solved: 150[Submit][Stat ...

  4. Exception: Could not bind to 0.0.0.0:8080 after trying for 30 seconds

    swift@vincent-virtual-machine /etc/swift $ sudo swift-init main restart Signal proxy-server pid: sig ...

  5. 【c++】动态内存

    静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.它主要存放静态数据.全局数据和常量.注意:const常量在定义时必须初始化 栈区:在执行函数时,函数内局部变量的存储单 ...

  6. javascript闭包诡异的问题

    var funcs = []; for (var i = 0; i < 3; i++) { // let's create 3 functions funcs[i] = function() { ...

  7. day5-WordCount

    1.   wordcount示例开发 1.1. wordcount程序整体运行流程示意图 map阶段: 将每一行文本数据变成<单词,1>这样的kv数据 reduce阶段:将相同单词的一组k ...

  8. [Unit Testing] Mock an HTTP request using Nock while unit testing

    When testing functions that make HTTP requests, it's not preferable for those requests to actually r ...

  9. Qt移动应用开发(四):应用粒子特效

    Qt移动应用开发(四):应用粒子特效 上一篇文章介绍了Qt Quick是如何对帧动画进行支持的.帧动画的实现离不开状态机.而状态机.动画和状态切换(transitions)则是Qt框架的核心内容.也就 ...

  10. Android第一个个人APP(帐号助手)

    第一个app上线了,关于帐号保存的一个app.本地保存,无须联网. 下载地址为:http://android.myapp.com/myapp/detail.htm?apkName=com.weeky. ...