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


    1937: [Shoi2004]Mst 最小生成树

    Time Limit: 3 Sec  Memory Limit: 64 MB
    Submit: 802  Solved: 344
    [Submit][Status][Discuss]

    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--->边权

    Source

    [Submit][Status][Discuss]

    注意到我们只可能增大树边,减小非树边,那么设每条边的改动幅度为$|d[i]|$,那么对于一条树边i和非树边j,必有$w[i]-d[i] leqslant w[j]+d[j]$,即$w[i]-w[j] leqslant d[i]+d[j]$。于是我们把边看作点,按是否为树边将所有边分成二分图,树边i与非树边j的边设为w[i]-w[j]。可以发现d[i]实际上就是KM算法中的顶标。所以求一次KM算法并将所有匹配相加就是答案,因为不在匹配里的d[i]直接作为0即可。

    重新复习一下KM算法。先将X部分的d[x]设为$max{w[x][y]}$,Y部分的d[y]设为0,然后求m次增广(直到有完备匹配)。每次增广如果失败,则设$mn=min{a[i]+b[j]-w[i][j]}$,将所有交错树上的d[x]+=mn,d[y]-=mn。

    理论依据:若由二分图中所有满足A[i]+B[j]=w[i][j]的边<i,j>构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。所以这是一个不断修改顶标并在相等子图上做完备匹配的过程。(任意i,j保证$d[i]+d[j] geqslant w[i][j]$)。

    定理:每次增广顶标和必然变小,最后一定是满足$d[i]+d[j] geqslant w[i][j]$的最小可能。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mem(a,k) memset(a,k,sizeof(a))
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 using namespace std;
     7 
     8 const int N=2000100,inf=0x3f3f3f3f;
     9 int n,m,u,v,ww,x,y,ans;
    10 int mp[60][60],w[1010][1010],lk[1010],lx[1010],ly[1010],vx[1010],vy[1010],s[1010],dep[60],fa[60][12];
    11 bool chk[60][60];
    12 struct E{ int u,v,w;}e[1010];
    13 
    14 void dfs(int x,int f){
    15     fa[x][0]=f; dep[x]=dep[f]+1;
    16     rep(i,1,10) fa[x][i]=fa[fa[x][i-1]][i-1];
    17     rep(i,1,n) if (i!=f && chk[x][i]) dfs(i,x);
    18 }
    19 
    20 int LCA(int x,int y){
    21     if (dep[x]<dep[y]) swap(x,y);
    22     int t=dep[x]-dep[y];
    23     for (int i=10; ~i; i--) if (t&(1<<i)) x=fa[x][i];
    24     if (x==y) return x;
    25     for (int i=10; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    26     return fa[x][0];
    27 }
    28 
    29 bool find(int x){
    30     vx[x]=1;
    31     rep(y,1,m) if (!vy[y]){
    32         int t=lx[x]+ly[y]-w[x][y];
    33         if (t==0){
    34             vy[y]=1; if (lk[y]==-1 || find(lk[y])) { lk[y]=x; return 1; }
    35         }else s[y]=min(s[y],t);
    36     }
    37     return 0;
    38 }
    39 
    40 void KM(){
    41     mem(lk,-1); mem(lx,-inf); mem(ly,0);
    42     rep(i,1,m) rep(j,1,m) lx[i]=max(lx[i],w[i][j]);
    43     rep(x,1,m){
    44         rep(i,1,m) s[i]=inf;
    45         while (1){
    46             mem(vx,0); mem(vy,0);
    47             if (find(x)) break;
    48             int d=inf;
    49             rep(i,1,m) if (!vy[i]) d=min(d,s[i]);
    50             rep(i,1,m) if (vx[i]) lx[i]-=d;
    51             rep(i,1,m) if (vy[i]) ly[i]+=d; else s[i]-=d;
    52         }
    53     }
    54     rep(i,1,m) if (lk[i]!=-1) ans+=w[lk[i]][i];
    55 }
    56 
    57 int main(){
    58     scanf("%d%d",&n,&m);
    59     rep(i,1,m) scanf("%d%d%d",&u,&v,&ww),e[i]=(E){u,v,ww},mp[u][v]=mp[v][u]=i;
    60     rep(i,2,n) scanf("%d%d",&x,&y),chk[x][y]=chk[y][x]=1;
    61     dfs(1,0);
    62     rep(i,1,m){
    63         int x=e[i].u,y=e[i].v,lca=LCA(x,y);
    64         if (!chk[x][y]){
    65             while (x!=lca) w[mp[x][fa[x][0]]][i]=e[mp[x][fa[x][0]]].w-e[i].w,x=fa[x][0];
    66             while (y!=lca) w[mp[y][fa[y][0]]][i]=e[mp[y][fa[y][0]]].w-e[i].w,y=fa[y][0];
    67         }
    68     }
    69     KM(); printf("%d
    ",ans);
    70     return 0;
    71 }

    好久没写最大费用最大流了发现自己完全不会写,调了整整一上午。需要注意:dis[]初始要赋为-inf,bfs()返回真的条件是dis[T]>0,其余不变。因为边里会有负值。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=2000100,inf=0x3f3f3f3f;
    10 int n,m,u,v,w,x,y,S,T,mn,cnt=1,ans;
    11 int to[N],f[N],c[N],nxt[N],h[1010],pre[1010],dis[1010],q[N];
    12 int mp[60][60],dep[60],fa[60][12];
    13 bool inq[N],chk[60][60];
    14 struct E{ int u,v,w;}e[1010];
    15 
    16 void add(int u,int v,int w,int co){
    17     to[++cnt]=v; f[cnt]=w; c[cnt]=co; nxt[cnt]=h[u]; h[u]=cnt;
    18     to[++cnt]=u; f[cnt]=0; c[cnt]=-co; nxt[cnt]=h[v]; h[v]=cnt;
    19 }
    20 
    21 bool spfa(){
    22     rep(i,0,T) dis[i]=-inf,pre[i]=-1,inq[i]=0;
    23     dis[S]=0; inq[S]=1; q[1]=S;
    24     for (int st=0,ed=1; st!=ed; ){
    25         int x=q[++st]; inq[x]=0;
    26         For(i,x) if (f[i] && dis[k=to[i]]<dis[x]+c[i]){
    27             dis[k]=dis[x]+c[i]; pre[k]=i;
    28             if (!inq[k]) inq[k]=1,q[++ed]=k;
    29         }
    30     }
    31     return dis[T]>0;
    32 }
    33 
    34 void mcmf(){
    35     for (ans=0; spfa(); ans+=dis[T]*mn){
    36         mn=inf;
    37         for (int i=pre[T]; ~i; i=pre[to[i^1]]) mn=min(mn,f[i]);
    38         for (int i=pre[T]; ~i; i=pre[to[i^1]]) f[i]-=mn,f[i^1]+=mn;
    39     }
    40 }
    41 
    42 void dfs(int x,int f){
    43     fa[x][0]=f; dep[x]=dep[f]+1;
    44     rep(i,1,10) fa[x][i]=fa[fa[x][i-1]][i-1];
    45     rep(i,1,n) if (i!=f && chk[x][i]) dfs(i,x);
    46 }
    47 
    48 int LCA(int x,int y){
    49     if (dep[x]<dep[y]) swap(x,y);
    50     int t=dep[x]-dep[y];
    51     for (int i=10; ~i; i--) if (t&(1<<i)) x=fa[x][i];
    52     if (x==y) return x;
    53     for (int i=10; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    54     return fa[x][0];
    55 }
    56 
    57 int main(){
    58     freopen("bzoj1937.in","r",stdin);
    59     freopen("bzoj1937.out","w",stdout);
    60     scanf("%d%d",&n,&m);
    61     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),e[i]=(E){u,v,w},mp[u][v]=mp[v][u]=i;
    62     rep(i,2,n) scanf("%d%d",&x,&y),chk[x][y]=chk[y][x]=1;
    63     dfs(1,0); S=m+1; T=m+2;
    64     rep(i,1,m){
    65         int x=e[i].u,y=e[i].v;
    66         if (chk[x][y]) add(S,i,1,0);
    67         else{
    68             add(i,T,1,0); int lca=LCA(x,y);
    69             while (x!=lca) add(mp[x][fa[x][0]],i,1,e[mp[x][fa[x][0]]].w-e[i].w),x=fa[x][0];
    70             while (y!=lca) add(mp[y][fa[y][0]],i,1,e[mp[y][fa[y][0]]].w-e[i].w),y=fa[y][0];
    71         }
    72     }
    73     mcmf(); printf("%d
    ",ans);
    74     return 0;
    75 }

     

  • 相关阅读:
    去除图片水印
    CALayer
    UIKit Animation
    CoreAnimation
    3DTouch
    键盘事件
    weChat聊天发送图片带有小尖角的实现
    webView 和 js 交互 之 屏蔽 样式
    iOS socket编程
    tableView尾部多处一部分空白高度
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8663628.html
Copyright © 2020-2023  润新知