最小生成树 水题集

来源:互联网 发布:彩票网络开售最新消息 编辑:程序博客网 时间:2024/06/05 21:02

先说求无向图最小生成树的两种算法:

①Prim算法

1.初始时两个集合V,E,初始时V为空,E是所有点的集合。

2.以图中任意一个点为起始点,把这点加入集合V,然后从集合E中删除,然后更新这个点到其它点的距离,如果更新不到的点,那么之间的距离为无穷大。

3.然后挑选离起始点最近的点,把这点加入集合V,然后从集合E中删除(有多个的话任选一个),然后更新  新加入的点  到其它点的距离,然后再找出一个距离这个集合最近的点(这个距离最近的点可能离起始点最近)。

4.然后重复上面的步骤,直至路被更新完或E为空,如果E不为空,说明图不连通。

②克鲁斯卡尔算法

1.将两点之间的距离排序

2.每次从中选出距离最短的两点,判断这两点所在的集合是否联通。

3.如果联通,继续步骤2;如果不连通,将两点合并为一个集合,继续步骤2

4.直至所有点都联通,或路径判断完毕

其中稠密图适合用prim,稀疏图适合用克鲁斯卡尔。

两个算法的基础都是贪心算法,下面的水题,练练手。。。

 

Hdu  1102  Constructing Roads

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102

题目大意:给你一个矩阵map,其中map[i][j]表示从i到j的花费,给你多次询问,输出询问的两点之间联通的最小花费

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110int map[N][N],visit[N],low[N];int n,m;int prim(){    int Min,sum=0,pos,i,j;    memset(visit,0,sizeof(visit));    visit[1]=1;pos=1;    for(int i=1;i<=n;i++)        if(i!=pos)        low[i]=map[pos][i];    for(int i=1;i<n;i++)    {        Min=Maxint;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]<Min)            {                Min=low[j];                pos=j;            }        sum+=Min;        visit[pos]=1;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]>map[pos][j])            low[j]=map[pos][j];    }    return sum;}int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)        {scanf("%d",&map[i][j]);map[j][i]=map[i][j];}        scanf("%d",&m);        int a,b;        for(int i=1;i<=m;i++)        {            scanf("%d%d",&a,&b);            map[a][b]=map[b][a]=0;        }        printf("%d\n",prim());    }    return 0;}


Hdu  1863  畅通工程

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863

题目大意:中文题,不解释

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110int n,m,rank,map[N][N],sum,f[N];//克鲁斯卡尔struct point{int x,y,dis;point():x(0),y(0),dis(0){}//结构体的初始化}s[N];bool cmp(point a,point b){    return a.dis<b.dis;}void init(){    sum=0;    rank=m;    for(int i=0;i<=N;i++)        f[i]=i;}int find(int x){    if(x!=f[x]) f[x]=find(f[x]);    return f[x];}int merge(point a){    int fx=find(a.x);    int fy=find(a.y);    if(fx!=fy)    {        f[fx]=fy;        sum+=a.dis;        rank--;    }    return rank;}int main(){    while(scanf("%d%d",&n,&m)&&n)    {        init();        for(int i=0; i<n; i++)            scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].dis);        sort(s,s+n,cmp);        int i;        for(i=0;i<n;i++)        {            if(merge(s[i])==1)            {printf("%d\n",sum);break;}        }        if(rank>1)            printf("?\n");    }    return 0;}

 

Hdu  1875   畅通工程再续

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1875

代码如下:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110//primint visit[N],n;double low[N],map[N][N];struct point{int x;int y;}s[N];void init()//初始化{    for(int i=0;i<N;i++)        for(int j=0;j<N;j++)        {            if(i==j) map[i][j]=0;            else map[i][j]=Maxint;        }}double prim(){    double Min,sum=0;    int pos,i,j;    memset(visit,0,sizeof(visit));    visit[0]=1;pos=0;    for(int i=0;i<n;i++)        if(i!=pos)        low[i]=map[pos][i];    for(int i=1;i<n;i++)    {        Min=Maxint;        for(int j=0;j<n;j++)            if(visit[j]==0&&low[j]<Min)            {                Min=low[j];                pos=j;            }        if(Min==Maxint) return -1;        sum+=Min;        visit[pos]=1;        for(int j=0;j<n;j++)            if(visit[j]==0&&low[j]>map[pos][j])            low[j]=map[pos][j];    }    return sum;}double S(point a,point b)//两坐标之间距离{    double len;    len=sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));    return len;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        init();        for(int i=0;i<n;i++)            scanf("%d%d",&s[i].x,&s[i].y);        for(int i=0;i<n;i++)            for(int j=i+1;j<n;j++)            {                double len=S(s[i],s[j]);                if(len>=10&&len<=1000)                    map[i][j]=map[j][i]=len*100;            }        double ans=prim();        if(ans==-1) printf("oh!\n");        else printf("%.1lf\n",ans);    }    return 0;}


 

Hdu  1879  继续畅通工程

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1879

代码如下:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110//primstruct point{int x,y,dis,f;}s[100005];      //注意s的范围int visit[N],n,low[N],map[N][N];void init(){    for(int i=0;i<N;i++)        for(int j=0;j<N;j++)        {            if(i==j) map[i][j]=0;            else map[i][j]=Maxint;        }}int prim(){    int Min,sum=0;    int pos,i,j;    memset(visit,0,sizeof(visit));    visit[1]=1;pos=1;    for(int i=1;i<=n;i++)        if(i!=pos)        low[i]=map[pos][i];    for(int i=1;i<n;i++)    {        Min=Maxint;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]<Min)            {                Min=low[j];                pos=j;            }        sum+=Min;        visit[pos]=1;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]>map[pos][j])            low[j]=map[pos][j];    }    return sum;}int main(){    while(scanf("%d",&n)&&n)    {        int a=n*(n-1)/2;        init();        for(int i=0; i<a; i++)        {            scanf("%d%d%d%d",&s[i].x,&s[i].y,&s[i].dis,&s[i].f);            if(s[i].f==1) map[s[i].x][s[i].y]=map[s[i].y][s[i].x]=0;            else map[s[i].x][s[i].y]=map[s[i].y][s[i].x]=s[i].dis;        }        printf("%d\n",prim());    }    return 0;}


Hdu  3371  Connect the Cities

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3371

题目大意:有N个城市,M条路,并且在输完路之后,再输入K个城市群,每个城市群里有P个城市相连,这P个城市之间的花费为0,求所有城市相连的最小花费,不能全部相连输出-1.

注意:代码用G++超时,用C++ 500ms AC

代码如下:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 510int visit[N],n,low[N],map[N][N],v[N];void init(){    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)        {            if(i==j) map[i][j]=0;            else map[i][j]=map[j][i]=Maxint;        }}int prim(){    int Min,sum=0;    int pos,i,j;    memset(visit,0,sizeof(visit));    visit[1]=1;pos=1;    for(int i=1;i<=n;i++)        if(i!=pos)        low[i]=map[pos][i];    for(int i=1;i<n;i++)    {        Min=Maxint;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]<Min)            {                Min=low[j];                pos=j;            }        if(Min==Maxint) return -1;        sum+=Min;        visit[pos]=1;        for(int j=1;j<=n;j++)            if(visit[j]==0&&low[j]>map[pos][j])            low[j]=map[pos][j];    }    return sum;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int m,k,num;        scanf("%d%d%d",&n,&m,&k);        init();        int a,b,c;        for(int i=1; i<=m; i++)        {            scanf("%d%d%d",&a,&b,&c);            if(map[a][b]>c) map[a][b]=c,map[b][a]=c;        }        for(int i=1;i<=k;i++)        {            scanf("%d",&num);            for(int j=0;j<num;j++)                scanf("%d",&v[j]);            for(int j=0;j<num;j++)                for(int kk=j+1;kk<num;kk++)                map[v[kk]][v[j]]=map[v[j]][v[kk]]=0;        }        printf("%d\n",prim());    }    return 0;}


 

Hdu  3367  Pseudoforest  最大生成树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3367

题目大意:将所有的点相连的最大花费,但相连的图中最多只有一个环。

代码如下:

//克鲁斯卡尔#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 10005int f[N],visit[N];int sum;struct point{int x,y,dis;}s[100005];bool cmp(point a,point b){    return a.dis>b.dis;}void init(){    sum=0;    memset(visit,0,sizeof(visit));    for(int i=0;i<N;i++)        f[i]=i;}int find(int x){    if(x!=f[x]) f[x]=find(f[x]);    return f[x];}void merge(point a){    int fx=find(a.x);    int fy=find(a.y);    if(fx==fy&&visit[fx]==0)    {        sum+=a.dis;        visit[fx]=1;    }    else    {        if(visit[fx]==0&&visit[fy]==0)        {            f[fx]=fy;            sum+=a.dis;        }        else if(visit[fx]==0||visit[fy]==0)        {            visit[fx]=1;            visit[fy]=1;            f[fx]=fy;            sum+=a.dis;        }    }}int main(){    int n,m;    while(scanf("%d%d",&n,&m)&&n+m)    {        init();        for(int i=0;i<m;i++)            scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].dis);        sort(s,s+m,cmp);        for(int i=0;i<m;i++)            merge(s[i]);        printf("%d\n",sum);    }    return 0;}

 

关于有向图的最小生成树,应该是最小树形图,会在接下来整理。。。


 

0 0
原创粉丝点击