poj3164最小树形图模板题

题目大意:给定一个有向图,根节点已知,求该有向图的最小树形图。最小树形图即有向图的最小生成树,定义为:选择一些边,使得根节点能够到达图中所有的节点,并使得选出的边的边权和最小。

题目算法:朱-刘算法(即由中国人朱永津和刘振宏共同发明的算法)。

算法步骤如下:

1.判断图的连通性,若不连通直接无解,否则一定有解。

2.为除了根节点以外的所有点选择一个权值最小的入边,假设用pre数组记录前驱,f数组记录选择的边长,记所选边权和为temp。

3.(可利用并查集)判断选择的的边是否构成环,若没有则直接ans+=temp并输出ans,若有,则进行下一步操作。

4.对该环实施缩点操作,设该环上有点V1,V2……Vi……Vn,缩成的点为node ,对于所有不在环中的点P进行如下更改:

(1) 点P到node的距离为min{a[p,Vi]-f[Vi]} (a为边集数组)

(2)点node到p的距离为min{a[Vi,p]}

操作(1)的理解:先假设环上所有边均选上,若下次选择某一条边进入该环,则可以断开进入点与进入点的前驱之间的边,即断开F[进入点],所以等效为直接把a[p,node]赋值为min{a[p,Vi]-f[Vi]}。

特别提醒:本题有自环,可以提前删掉,因为它没有用。

最后G++double输出lf会wa,改成f就好了,或者用c++提交

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cassert>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

const double g=10.0,eps=1e-9;
const int N=100+10,maxn=100000+10,inf=0x3f3f3f;

double x[N],y[N];
int n,m;
int pre[N];
bool vis[N],in[N];
double w[N][N];
double dis(int a,int b)
{
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=1;i<=n;i++)
        if(!vis[i]&&w[u][i]<inf)
           dfs(i);
}
double dirmst(int u)
{
    double ans=0;
    dfs(u);
    for(int i=1;i<=n;i++)
        if(!vis[i])
          return -1;
    memset(vis,0,sizeof vis);
    while(1){
        for(int i=1;i<=n;i++)
        {
            if(i!=u&&!in[i])
            {
                w[i][i]=inf;
                pre[i]=i;
                for(int j=1;j<=n;j++)
                    if(!in[j]&&w[j][i]<w[pre[i]][i])
                        pre[i]=j;
            }
        }
        int i;
        for(i=1;i<=n;i++)
        {
            if(i!=u&&!in[i])
            {
                int j=i,cnt=0;
                while(j!=u&&pre[j]!=i&&cnt<=n)cnt++,j=pre[j];
                if(j==u||cnt>n)continue;
                break;
            }
        }
        if(i>n)
        {
            for(int j=1;j<=n;j++)
                if(j!=u&&!in[j])
                    ans+=w[pre[j]][j];
            return ans;
        }
        int j=i;
        memset(vis,0,sizeof vis);
        do{
            ans+=w[pre[j]][j],j=pre[j],vis[j]=in[j]=1;
        }while(j!=i);
        in[i]=0;
        for(int k=1;k<=n;k++)
            if(vis[k])
               for(int j=1;j<=n;j++)
                  if(!vis[j])
                  {
                      if(w[i][j]>w[k][j])w[i][j]=w[k][j];
                      if(w[j][k]<inf&&w[j][k]-w[pre[k]][k]<w[j][i])
                        w[j][i]=w[j][k]-w[pre[k]][k];
                  }
    }
    return ans;
}
int main()
{
  /*  ios::sync_with_stdio(false);
    cin.tie(0);
    cout<<setiosflags(ios::fixed)<<setprecision(2)<<endl;*/
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=n;i++)
        {
            vis[i]=in[i]=0;
            for(int j=1;j<=n;j++)
                w[i][j]=inf;
        }
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            if(a==b)continue;
            w[a][b]=dis(a,b);
        }
      /*  for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                cout<<w[i][j]<<" ";
            cout<<endl;
        }*/
        double ans=dirmst(1);
        if(ans<0)printf("poor snoopy\n");
        else printf("%.2f\n",ans);
    }
    return 0;
}

最小树形图

时间: 2024-10-12 08:51:14

poj3164最小树形图模板题的相关文章

【POJ3164】Command Network 最小树形图模板题 重修版

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44935891"); } 我以前的版本 算法构造过程以及傻叉代码+弱版注释见以前博客 http://blog.csdn.net/vmurder/article/details/38819711 最小树形图: 名词解释: 其实就是有向图

POJ 3164 Command Network(最小树形图模板题+详解)

http://poj.org/problem?id=3164 题意: 求最小树形图. 思路: 套模板. 引用一下来自大神博客的讲解:http://www.cnblogs.com/acjiumeng/p/7136604.html 算法步骤如下: 1.判断图的连通性,若不连通直接无解,否则一定有解. 2.为除了根节点以外的所有点选择一个权值最小的入边,假设用pre数组记录前驱,f数组记录选择的边长,记所选边权和为temp. 3.(可利用并查集)判断选择的的边是否构成环,若没有则直接$ans+=tem

无根最小树形图模板

1 #include<iostream> 2 using namespace std; 3 #include<cstdio> 4 #include<cstring> 5 #define MAXN 1005 6 #define INF 0x7f7f7f7f 7 typedef __int64 type; 8 struct node//边的权和顶点 9 { 10 int u, v; 11 type w; 12 }edge[MAXN * MAXN]; 13 int pre[M

poj 3164 最小树形图模板!!!

/* tle十几次,最后发现当i从1开始时,给环赋值时要注意啊! 最小树形图 */ #include<stdio.h> #include<string.h> #include<math.h> #define N 110 #define inf 0x3fffffff #define eps 1e-10 struct node { int u,v; double w; }edge[N*N*2]; double distance (double x,double y,doub

朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】

什么是最小树形图?相信大家如果会过来看这篇文章,想必也应该对最小生成树有所了解的,最小生成树求的是无向图的一颗生成树的最小权值.我们的最小树形图就是来解决一个有向图的一颗生成树的最小权值,对于度娘来说,最小树形图是这样定义的:最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小. 通解最小树形图的一种算法是是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法:朱.刘算法. 今天我们就来浅谈一下最小树形图的问题. 大题上完整的朱

hdu4009最小树形图板子题

/*调了一下午的最小树形图,昨天刚刚看懂模板..最小树形图,就是有向图的最小生成树,很神奇==*/ #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define MAXN 1002 #define INF 0x3f3f3f3f using namespace std; struct Node{ int x,y,z; }nodes[MAXN]; struct Edge

poj 3164 最小树形图模板 (优先c++ ,g++ 有时会wa==)

#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include <iostream> #define eps 1e-8 using namespace std; /* 最小树形图图模版-朱刘算法 模版说明:点标号必须0-(N-1) 必须去除到自身的点(到自身的边的边权赋无限大) */ #define M 109 #define type double

最小树形图(模板)

本文链接:http://www.cnblogs.com/Ash-ly/p/5536796.html 定义: 设G = (V, E)是一个有向图,如果具有下述性质 (1)G中不包含有向环; (2)存在一个顶点vi,它不是任何弧的终点,而V的其它顶点都恰好是唯一的一条弧的终点.则称 G是以vi为根的树形图. 最小树形图就是有向图G = (V, E)中以vi为根的树形图中权值的和最小的那一个. 用朱刘算法求最小树形图: 最小树形图基于贪心和缩点的思想,所谓缩点,就是将几个点看成一个点,所有连到这几个点

poj 3041Asteroids 二分匹配求最小点覆盖模板题

//最大匹配=最小覆盖 //这题是求最小覆盖点的模板题 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 510; int line[maxn][maxn]; int match[maxn]; int vis[maxn]; int N , K; int find(int start) { for(int i = 1;i <=  N;