zoukankan      html  css  js  c++  java
  • BZOJ 1937: [Shoi2004]Mst 最小生成树

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

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

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

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

    [w_x-d_xle w_y+d_yLeftrightarrow d_x+d_yge 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;
    }
    
  • 相关阅读:
    Teacher Bo HDU 5762(暴力)
    The Unique MST POJ1679(次小生成树)
    Sqrt Bo hdu 5752
    Borg Maze POJ 3026(BFS+最小生成树)
    Highways POJ 1751(最小生成树)
    hdu---2050---折线分割平面
    POj---1469---Courses
    poj---2349---Arctic Network
    poj-2528-Mayor's posters
    POJ---3468---A Simple Problem with Integers
  • 原文地址:https://www.cnblogs.com/cjjsb/p/12240328.html
Copyright © 2011-2022 走看看