朱刘算法

干什么的

朱刘算法就是最小生成树算法在有向图上的应用。

大概说说

给定一个有向图,有向图定义一个根节点,求一个最小树形图。

树形图就是一颗有向树。

而在这个算法中我们要给定几个条件:

  • 没有有向环

  • 每个点的入度为1(除了根节点之外)

放在题目中看

POJ 3164/AcWing 2417

先贪心的从每个点的所有入边中找一条权值最小的边,从选出的边中判断是否存在环;
如果不存在环,结束,把所有边权值加上作为答案;如果存在环,进入下一步。将所有环缩点,构造新图,缩点前把所有边权值加上。每次缩一次点,点数最少减一,所以总共最多迭代 \(n\) 次算法结束。

#include<bits/stdc++.h>

#define rint register int
#define int long long

#define endl '\n'
#define x first
#define y second

using namespace std;

const int N = 1e2;

int n,m;
pair<double,double> q[N];
bool g[N][N],st[N],ins[N];
double d[N][N], bd[N][N];
int pre[N],bpre[N],dfn[N],low[N],ts,stk[N],top,id[N],cnt;

void inline dfs(int u){
    st[u]=1;
    for(rint i=1;i<=n;i++){
        if(g[u][i]&&!st[i]){
            dfs(i);        	
		}    	
	}
    return ;
}

bool inline check_con(){
    memset(st,0,sizeof st);
    dfs(1);
    for(rint i=1;i<=n;i++){
        if(!st[i]){
            return 0;            	
		}
    }
    return 1;
}

double inline get_dist(int a,int b){
    double dx=q[a].x-q[b].x,dy=q[a].y-q[b].y;
    return sqrt(dx*dx+dy*dy);
}

void inline tarjan(int u){
    dfn[u]=low[u]=++ts;
    stk[++top]=u;
	ins[u]=1;
    int j=pre[u];
    if(!dfn[j]){
        tarjan(j);
        low[u]=min(low[u],low[j]);
    }else if(ins[j]){
		low[u]=min(low[u], dfn[j]);
	}if(low[u]==dfn[u]){
        int y;cnt++;
        do{
            y=stk[top--];
			ins[y]=0; 
			id[y]=cnt;
        }while(y!=u);
    }
    return ;
}

double inline work(){
    double res=0;
    for(rint i=1;i<=n;i++){
	    for(rint j=1;j<=n;j++){
		    if(g[i][j]){
			    d[i][j]=get_dist(i,j);		    	
			}else{
			    d[i][j]=0x3f3f3f3f;	   				
			}
		}    	
	}

    while(true){
        for(rint i=1;i<=n;i++){
            pre[i]=i;
            for(rint j=1;j<=n;j++){
                if(d[pre[i]][i]>d[j][i]){
                	pre[i]=j;
				}           	
			}        
        }

        memset(dfn,0,sizeof dfn);
        ts=cnt=0;
        
        for(rint i=1;i<=n;i++){
            if(!dfn[i]){
            	tarjan(i);
			}        	
		}     

        if(cnt==n){
            for(rint i=2;i<=n;i++) 
			    res+=d[pre[i]][i];
            break;
        }

        for(rint i=2;i<=n;i++){
            if(id[pre[i]]==id[i]){
            	res+=d[pre[i]][i];
			}	
		}     

        for(rint i=1;i<=cnt;i++)
            for(rint j=1;j<=cnt;j++)
                bd[i][j]=0x3f3f3f3f;

        for(rint i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                if(d[i][j]<0x3f3f3f3f&&id[i]!=id[j]){
                    int a=id[i];
					int b=id[j];
                    if(id[pre[j]]==id[j]){
                    	bd[a][b]=min(bd[a][b],d[i][j]-d[pre[j]][j]);
					}else{
                    	bd[a][b]=min(bd[a][b],d[i][j]);
					} 
                }

        n=cnt;
        memcpy(d,bd,sizeof d);
    }

    return res;
}

signed main(){
    while(~scanf("%lld%lld",&n,&m)){
        for(rint i=1;i<=n;i++) 
		    cin>>q[i].x>>q[i].y;

        memset(g,0,sizeof g);
        while(m--){
            int a,b;
            cin>>a>>b;
            if(a!=b&&b!=1) 
			    g[a][b]=1;
        }

        if(!check_con()){
        	puts("poor snoopy");
		}else{
			printf("%.2lf\n", work());
		} 
    }

    return 0;
}

posted @ 2022-07-15 10:14  PassName  阅读(301)  评论(0编辑  收藏  举报