朱刘算法

有这样一类问题:一个n个点m条边的有向图中,找到一颗总边权最小的生成树,使得根节点能到达任意一个点(这样的一颗树就叫做这个图的最小树形图);

我们怎么暴力怎么来:

1.首先,我们对于图中的每个点y求出所有出边指向y中边权最小的点x,对于(x,y)建立父子关系;2.

2.然后我们按照这个关系得到一个图,由于自环不可能出现在生成树中,所有清除所有的自环;

3.如果这个图不存在强联通分量(环),那么这棵树就是一个最小树形图;

4.如果不是呢?我们将图中每个强联通分量缩成一个点,表示这个强联通分量中所有边都会选择;

5.然显然,这个强联通分量中不可能选取所有的边,那么采取可反悔贪心的思想:把所有出边指向这个(强联通分量中的点x)的(边权w)减去(与点x存在父子关系的点y)之间的(边权k),这意味着如果以后要选择边w,那么就要断去边k,额外的代价就是w-k;

6.然后缩完点后得到一个新的图,重复步骤1,直到出现步骤3,此时的总代价便是最小树形图的边权最小值;

 

这就是朱刘算法(其实本质就带反悔贪心的暴力啦~)

#include 

using namespace std;

typedef long long ll;

const int maxn=1e2+50;
const int maxm=1e4+50;
const int inf=0x3f3f3f3f;

int n,m,r;
ll ans;

inline int read() {
    int a=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+c-'0',c=getchar();
    return a;
}

struct edge {int u,v,w;}e[maxm];

int cnt,fa[maxn],id[maxn],top[maxn],min[maxn];
//cnt当前图环的数量 
//id[u]代表u节点在第id[u]个环中
//top[u]代表u所在链的代表元素 类似并查集 
//min[u]为当前连到u点的最短边的边权 fa[v]当前连到v点的最短边的u 

inline int getans() {
    while(1) {
        for(register int i=1;i<=n;++i) id[i]=top[i]=0,min[i]=inf;
        for(register int i=1;i<=m;++i)
            if(e[i].u!=e[i].v&&e[i].w 
 

你可能感兴趣的:(朱刘算法)