ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BZOJ 1937: [Shoi2004]Mst 最小生成树

2020-01-29 15:03:10  阅读:239  来源: 互联网

标签:dep CI Shoi2004 int Mst 非树边 fa 1937 now


我称之为重拾KM(好久以前学的然后现在忘得差不多了)?

首先我们容易想到把每一条非树边拿出来,它显然会和一些树边形成一个环

那么那些树边是最小生成树上的边的充要条件显然是它们的边权都小于等于这条非树边

考虑树边的权值必然是减少的,非树边的权值必然是增加的,我们设\(x\)为树边,\(y\)为非树边,那么:

\[w_x-d_x\le w_y+d_y\Leftrightarrow d_x+d_y\ge w_x-w_y\]

考虑这里的\(w_x-w_y\)是一个定值,那么我们发现上面那个式子恰好是KM算法中顶标边权的关系

而这里的要求恰好是最小化\(\sum_i d_i\),同样满足KM结束的条件,因此直接做就是了

PS:貌似还可以直接对偶化成线性规划问题上单纯形的做法,不够没这个直观。好吧是我不会单纯形

#include<cstdio>
#include<vector>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1005,INF=1e9;
struct data
{
    int x,y,w;
}e[N]; int n,m,x,y,id[N][N],anc[N],dep[N],w[N][N]; bool tr[N][N]; vector <int> E[N];
inline void addedge(CI x,CI y)
{
    E[x].push_back(y); E[y].push_back(x);
}
inline void DFS(CI now=1,CI fa=0)
{
    anc[now]=fa; dep[now]=dep[fa]+1;
    for (vector <int>:: iterator to=E[now].begin();to!=E[now].end();++to)
    if (*to!=fa) DFS(*to,now);
}
inline int LCA(int x,int y)
{
    if (dep[x]<dep[y]) swap(x,y); while (dep[x]!=dep[y]) x=anc[x];
    while (x!=y) x=anc[x],y=anc[y]; return x;
}
namespace KM
{
    int dx[N],dy[N],rsd[N],fr[N]; bool vx[N],vy[N];
    inline bool find(CI now)
    {
        vx[now]=1; for (RI to=1;to<=m;++to) if (!vy[to])
        {
            int dlt=dx[now]+dy[to]-w[now][to];
            if (!dlt) { vy[to]=1; if (!~fr[to]||find(fr[to])) return fr[to]=now,1; }
            else rsd[to]=min(rsd[to],dlt);
        }
        return 0;
    }
    inline int KM(int ret=0)
    {
        RI i,j; for (i=1;i<=m;++i) dx[i]=-INF,fr[i]=-1;
        for (i=1;i<=m;++i) for (j=1;j<=m;++j) dx[i]=max(dx[i],w[i][j]);
        for (i=1;i<=m;++i)
        {
            for (j=1;j<=m;++j) rsd[j]=INF; for (;;)
            {
                for (j=1;j<=m;++j) vx[j]=vy[j]=0; if (find(i)) break;
                int dlt=INF; for (j=1;j<=m;++j) if (!vy[j]) dlt=min(dlt,rsd[j]);
                for (j=1;j<=m;++j) if (vx[j]) dx[j]-=dlt;
                for (j=1;j<=m;++j) if (vy[j]) dy[j]+=dlt; else rsd[j]-=dlt;
            }
        }
        for (i=1;i<=m;++i) if (~fr[i]) ret+=w[fr[i]][i]; return ret;
    }
};
int main()
{
    RI i; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
    scanf("%d%d%d",&x,&y,&e[i].w),e[i].x=x,e[i].y=y,id[x][y]=id[y][x]=i;
    for (i=1;i<n;++i) scanf("%d%d",&x,&y),tr[x][y]=tr[y][x]=1,addedge(x,y);
    for (DFS(),i=1;i<=m;++i)
    {
        x=e[i].x; y=e[i].y; if (tr[x][y]) continue; int fa=LCA(x,y);
        while (x!=fa) w[id[anc[x]][x]][i]=e[id[anc[x]][x]].w-e[i].w,x=anc[x];
        while (y!=fa) w[id[anc[y]][y]][i]=e[id[anc[y]][y]].w-e[i].w,y=anc[y];
    }
    return printf("%d",KM::KM()),0;
}

标签:dep,CI,Shoi2004,int,Mst,非树边,fa,1937,now
来源: https://www.cnblogs.com/cjjsb/p/12240328.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有