2019_GDUT_新生专题 图论 畅通工程系列

1.畅通工程

链接:https://vjudge.net/contest/351234#problem/H

题目描述:给出图,加最少的边把点全连起来。

题目分析:把连通的点看作一个整体,把它们连起来。

代码:

#include <stdio.h>
#include <stdlib.h>
int n,m,nm;
int b[1001],c[1001],d[1001],e[1000][1000];//b[]记各点的根
struct Way                                //c[]笔记是否已走
{                                         //d[]记a[]中各起点的头
    int begin;
    int end;
}a[1000000];                              //存边
int comp(const void *p1,const void *p2)
{
    if ((*(struct Way*)p2).begin>(*(struct Way*)p1).begin) return -1;
    else return 1;
}
int dfs(int x,int y)
{
    int i;
    if(c[y]) return 0;
    c[y]=1;
    for(i=d[y];i<nm;i++)
    {
        if(a[i].begin!=y) break;
        b[a[i].end]=x;
        dfs(x,a[i].end);
    }
    return 0;
}
int main()
{
    int i,j,p,w,u;
    while(scanf("%d",&n)!=EOF&&n)
    {  scanf("%d",&m);
       for(i=1;i<=n;i++)      //初始化
       {
           for(j=1;j<=n;j++)
           {
               e[i][j]=0;
           }
       }
       for(i=0;i<m;i++)     //这里复杂化了,没必要用图存边
       {
           scanf("%d%d",&w,&u);
           e[w][u]=1;
           e[u][w]=1;
       }
       for(i=1,w=0;i<=n;i++)
       {
           for(j=1;j<=n;j++)
           {if(e[i][j]) {a[w].begin=i;a[w++].end=j;}}
       }
       nm=w;
       qsort(a,nm,sizeof(a[0]),comp);
       for(i=nm-1;i>=0;i--)
       {
           d[a[i].begin]=i;
       }
       for(i=1;i<=n;i++) b[i]=i;//初始化
       for(i=1;i<=n;i++) c[i]=0;
        for(i=1,p=0;i<=n;i++)
       {
           if(b[i]==i) {p++;dfs(i,i);}  //根据根判断是否DFS标记
       }
       printf("%d\n",p-1);//根的数目-1就是需连的路
    }
    return 0;
}

2.还是畅通工程(点击下面链接)
链接:https://blog.csdn.net/jian_ke/article/details/104010893

3.畅通工程续

题目链接:https://vjudge.net/contest/351234#problem/J

题目描述:判断是否能到达终点,如果能算最短路。

模板题不分析

代码:

#include <stdio.h>
#include <stdlib.h>
int n,m,f,s;
int b[201],c[201],d[201];
struct Way
{
    int begin;
    int end;
    int length;
}a[2002];
int comp(const void *p1,const void *p2)
{
    if ((*(struct Way*)p2).begin>(*(struct Way*)p1).begin) return -1;
    else return 1;
}
int dfs(int x)
{
    int i;
    c[x]=1;
    for(i=d[x];i<2*m;i++)
    {
        if(a[i].begin!=x) break;
        if(b[a[i].end]>b[a[i].begin]+a[i].length)
           {b[a[i].end]=b[a[i].begin]+a[i].length;
           if(c[a[i].end]==0&&a[i].end!=f) dfs(a[i].end);
           }
    }
    c[x]=0;
    return 0;
}
int main()
{
    int i;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
       for(i=0;i<2*m;i+=2)
       {
           scanf("%d%d%d",&a[i].begin,&a[i].end,&a[i].length);
           a[i+1].begin=a[i].end;
           a[i+1].end=a[i].begin;
           a[i+1].length=a[i].length;
       }
       scanf("%d%d",&s,&f);
       qsort(a,2*m,sizeof(a[0]),comp);
       for(i=2*m-1;i>=0;i--)
       {
           d[a[i].begin]=i;
       }
       for(i=0;i<n;i++) b[i]=1e9;
       b[s]=0;
       dfs(s);
       if(b[f]==1e9) printf("-1\n");
        else printf("%d\n",b[f]);
    }
    return 0;
}

3.畅通工程再续

题目链接:https://vjudge.net/contest/351234#problem/K

题目分析:这是求MST问题,只不过边权需要计算和判断是否有效。

代码:

#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
int g[105],h[105],n;//g[]标记根
double sum;         //h[]标记树高
struct Way
{
    int s,e;
    double cost;
}a[10000];
bool com(const struct Way &p1,const struct Way &p2)
{
    return p1.cost<p2.cost;
}
void chu() //初始函数
{
    int i;
    for(i=0;i<n;i++)
    {
        h[i]=0;
        g[i]=i;
    }
}
int fin(int x)  //找根函数
{
    if(g[x]==x) return x;
    return g[x]=fin(g[x]);
}
void unit(int x,int y)  //连接树的函数
{
    x=fin(x);
    y=fin(y);
    if(h[x]>h[y]) g[y]=g[x];
    else g[x]=g[y];
    if(h[fin(x)]==h[fin(y)])  h[fin(x)]++;
}
int main()
{
    int i,b[2][10000],j,y,x,k,t;//b[][]存点
    double l;
    scanf("%d",&t);
    while(t--)
    {   k=0,sum=0;
        scanf("%d",&n);
        chu();
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&b[0][i],&b[1][i]);
            if(i>0)
            {
                for(j=0;j<i;j++)
                {
                    x=b[0][i]-b[0][j];
                    y=b[1][i]-b[1][j];
                    l=x*x+y*y;            //算边的平方
                    if(100<=l&&l<=1e6)    //有效边存入
                    {
                        a[k].s=i;
                        a[k].e=j;
                        a[k++].cost=sqrt(l);
                        a[k].s=j;
                        a[k].e=i;
                        a[k].cost=a[k-1].cost;
                        k++;
                    }
                }
            }
        }
        sort(a,a+k,com);
        for(i=0,j=1;i<k;i++)//找MSP
        {
            if(fin(a[i].s)!=fin(a[i].e))
            {
                sum+=a[i].cost;
                unit(a[i].s,a[i].e);
                j++;//记录连点数
            }
        }
        if(j==n) printf("%.1lf\n",sum*100);
        else printf("oh!\n");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值