• 畅通工程系列相关题型


    上周花了一周多的时间看了最小生成树,最短路,并查集这一块内容,这是上周新学的知识点,时间拉的确实有点长,尤其是1875那一题卡了很久,用两种方法写比较混乱,虽然也是花了一周多的时间,但是也只会写写这些模板题,而且对于这些容易把代码掺杂在一起写,思路逻辑不清,这一点需要自己多去找找原因,理清思路。

    HDU1863-畅通工程

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<iostream>
    #include<map>
    using namespace std;
    
    #define inf 0x3f3f3f3f
    
    struct edge
    {
        int u;
        int v;
        int w;
    }e[110];
    
    int n,m;
    int f[110]={0};
    
    int cmp1(edge x,edge y)
    {
        return x.w<y.w;
    }
    
    void init()
    {
        for(int i=1;i<=m;i++)
            f[i]=i;
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=getf(f[x]);
    }
    
    int merge(int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if(t1!=t2)
        {
            f[t2]=t1;
            return 1;
        }
        return 0;
    }
    
    int main()
    {
        int i;
        while(~scanf("%d %d",&n,&m)&&n)
        {
            memset(e,0,sizeof(e));
            memset(f,0,sizeof(f));
            int sum=0,countt=0;
            for(i=1;i<=n;i++)
                scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
            init();
            sort(e+1,e+n+1,cmp1);
            int flag=0;
            for(i=1;i<=n;i++)
            {
                if(merge(e[i].u,e[i].v)!=0)
                {
                    countt++;
                    sum=sum+e[i].w;
                }
                if(countt==m-1)
                {
                    flag=1;
                }
            }
            if(flag==1)
                printf("%d\n",sum);
            else
                printf("?\n");
        }
        return 0;
    }
    

    HDU1874-畅通工程续

    AC代码:

    //floyd多源和dijkstra单源都可以写
    #include<algorithm>
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<math.h>
    #include<queue>
    #include<stack>
    #include<map>
    using namespace std;
    
    #define inf 0x3f3f3f3f
    
    int e[1010][1010],m,n;
    int dis[1010],book[1010],f[1010];
    
    void init()
    {
        for(int i=0; i<n; i++)
            f[i]=i;
        return ;
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=getf(f[x]);
    }
    
    int merge(int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if(t1!=t2)
        {
            f[t1]=t2;
            return 1;
        }
        return 0;
    }
    
    int main()
    {
        int i,j,m,n,st,en,u,k;
        while(~scanf("%d %d",&n,&m))
        {
            for(i=0; i<n; i++)//初始化
            {
                for(j=0; j<n; j++)
                {
                    if(i==j)
                        e[i][j]=0;
                    else
                        e[i][j]=inf;
                }
            }
    
            int t1,t2,t3;
            for(i=0; i<m; i++)
            {   //注意一下这边存的方法
                scanf("%d %d %d",&t1,&t2,&t3);
                //     e[t1][t2]=t3;//因为是双向的,所以不需要再反向存一遍
                if(t3<e[t1][t2]||t3<e[t2][t1])//需要两个城镇许多条道路的最短距离
                    //   e[t1][t2]=t3;
                    e[t1][t2]=e[t2][t1]=t3;
                //请在一行里输出最短需要行走的距离
            }
            scanf("%d %d",&st,&en);
            init();//初始化它们的头头 这一步好像用不到
    //        for(i=0;i<n;i++)
    //            dis[i]=e[st][i];
    //        for(i=0;i<n;i++)
    //        {
    //            book[i]=0;
    //        }
    //        bokok[st]=1;
    //
    //        int sum=0;
    //
    //        for(i=1;i<n;i++)//需要循环n-1次
    //        {
    //            int minn=inf;
    //            for(j=0;j<n;j++)
    //            {
    //                if(book[j]==0&&dis[j]<minn)
    //                {
    //                    minn=dis[j];
    //                    u=j;
    //                }
    //            }
    //
    //            book[u]=1;
    //            for(j=0;j<n;j++)
    //            {
    //                if(e[u][j]<inf)
    //                {
    //                    if(dis[j]>dis[u]+e[u][j])
    //                        dis[j]=dis[u]+e[u][k];
    //                }
    //            }
    //        }//单源
    
            for(k=0; k<n; k++)
            {
                for(i=0; i<n; i++)
                {
                    for(j=0; j<n; j++)
                    {
                        if(e[i][j]>e[i][k]+e[k][j])
                            e[i][j]=e[i][k]+e[k][j];
                    }
                }
            }
    //        int ans=0;
    //        for(i=0; i<n; i++)
    //        {
    //            if(f[i]==i)
    //                ans++;
    //        }
    //        if(ans==1)
    //            printf("%d\n",e[st][en]);
    //        else
    //            printf("-1\n");
    
            if(e[st][en]==inf)
                printf("-1\n");
            else
                printf("%d\n",e[st][en]);
        }
        return 0;
    }
    

    HDU1232-畅通工程

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<iostream>
    using namespace std;
    
    int f[1010],n,m;
    
    void init()
    {
        for(int i=1;i<=m;i++)
            f[i]=i;
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=getf(f[x]);
    }
    
    void merge(int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if(t1!=t2)
            f[t2]=t1;
        return ;
    }
    
    int main()
    {
        int i,x,y;
       // while(scanf("%d %d",&m,&n)&&(m!=0))//??
        while(scanf("%d %d",&m,&n)&&m)
        {
            init();
            for(i=1;i<=n;i++)
            {
                scanf("%d %d",&x,&y);
                merge(x,y);
            }
            int ans=0;
            for(i=1;i<=m;i++)
            {
                if(f[i]==i)
                    ans=ans+1;
            }
            printf("%d\n",ans-1);
        }
        return 0;
    }
    

    HDU1233-还是畅通工程

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<iostream>
    #include<map>
    using namespace std;
    
    #define inf 0x3f3f3f3f
    
    int f[10030]={0},i,n;//这里数组开小了会出现TLE
    
    struct E
    {
        int u;
        int v;
        int w;
    } e[10030];
    
    void init()
    {
        for(int i=1; i<=n; i++)
            f[i]=i;
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=getf(f[x]);
    }
    
    int merge(int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if (t1!=t2)
        {
            f[t2]=t1;
            return 1;
        }
        return 0;
    }
    
    int cmp1(E x,E y)
    {
        return x.w<y.w;
    }
    
    int main()
    {
        int i;
        while(~scanf("%d",&n)&&n)
        {
            int countt=0,sum=0;
            for(i=1; i<=n*(n-1)/2; i++)
                scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
            sort(e+1,e+n*(n-1)/2+1,cmp1);
            init();
            for(i=1; i<=n*(n-1)/2; i++)
            {
                if(merge(e[i].u,e[i].v)!=0)
                {
                    countt++;
                    sum=sum+e[i].w;
                }
                if(countt==n-1)
                    break;
            }
            printf("%d\n",sum);
        }
        return 0;
    }
    

    HDU1875-畅通工程再续

    有一个小细节:计算距离的时候,sqrt(double)需要处理一下,不然有些编译器会过不去,可以强制转换,可以+0.0,或者*1.0,根据编译器来。(我写的时候C++,G++强制转换都过不去,不知道为什么。。。)

    该题AC有两种方法,详情见下。

    最短路写的AC代码:

    #include<stdio.h>
    #include<math.h>
    
    #define inf 0x3f3f3f3f
    double e[110][110],dis[110];
    int a[110],b[110],book[110];
    
    double ss(int i,int j)
    {
        double d;
        d=sqrt((a[j]-a[i])*(a[j]-a[i])+(b[j]-b[i])*(b[j]-b[i]));
        return d;
    
    }
    int main()
    {
        int i,j,k,m,n,t,u;
        while(~scanf("%d",&t))
        {
            while(t--)
            {
                double sum=0,minn;
                scanf("%d",&n);
                for(i=1; i<=n; i++)
                    scanf("%d %d",&a[i],&b[i]);
                for(i=1; i<=n; i++)
                {
                    for(j=1; j<=n; j++)
                    {
                        if(i==j)
                            e[i][j]=0;
                        else
                            e[i][j]=inf;
                    }
                }
    
                for(i=1; i<=n; i++)
                {
                    for(j=1; j<=n; j++)
                    {
                        double kk=ss(i,j);
                        if(e[i][j]>kk&&kk>=10&&kk<=1000)
                        {
                            e[i][j]=e[j][i]=kk;
                        }
                    }
                }
    
                for(i=1; i<=n; i++)
                {
                    dis[i]=e[1][i];
                }
    
                for(i=1; i<=n; i++)
                {
                    book[i]=0;
                }
                book[1]=1;
    
                int flag=0;
                for(i=1; i<n; i++)
                {
                    minn=inf;
                    for(j=1; j<=n; j++)
                    {
                        if(book[j]==0&&dis[j]<minn)
                        {
                            minn=dis[j];
                            u=j;
                        }
                    }
                    if(minn==inf)
                    {
                        flag=1;
                        printf("oh!\n");
                        break;
                    }
                    sum=sum+minn*1.0;
                    book[u]=1;
                    for(k=1; k<=n; k++)
                    {
                        if(e[u][k]<inf&&dis[k]>e[u][k])
                            dis[k]=e[u][k];// dis[k]=dis[u]+e[u][k];这里的错误注意一下
                    }
                }
    //
    //            for(i=1; i<=n; i++)
    //            {
    //                if(dis[i]==inf)
    //                {
    //                    flag=1;
    //                    break;
    //                }
    //            }
    //            if(flag==1)
    //            {
    //                printf("oh!\n");
    //                continue;
    //            }
                if(flag==0)
                    printf("%.1lf\n",sum*100);
            }
        }
    }
    

    并查集+最小生成树写的AC代码:

    //并查集+最小生成树
    #include<stdio.h>
    #include<math.h>
    #include<algorithm>
    #include<string.h>
    #define inf 0x3f3f3f3f
    using namespace std;
    
    int dis[110],e[110][110];
    int a[110],b[110],f[110]= {0},n;
    
    
    double ss(int i,int j)
    {
        double d;
        d=sqrt((a[j]-a[i])*(a[j]-a[i])+(b[j]-b[i])*(b[j]-b[i]));
        return d;
    
    }
    void init()
    {
        for(int i=1; i<=n; i++)
        {
            f[i]=i;
        }
        return ;
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        else
            return f[x]=getf(f[x]);
    }
    
    int merge (int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if(t1!=t2)
        {
            f[t2]=t1;
            return 1;
        }
        return 0;
    }
    
    struct node
    {
        int x;
        int y;
        double w;
    } dd[110100];
    
    int cmp1(node x,node y)
    {
        return x.w<y.w;
    }
    int main()
    {
        int i,j,k,m,t;
        while(~scanf("%d",&t))
        {
            while(t--)
            {
                scanf("%d",&n);
                memset(a,0,sizeof(a));
                memset(b,0,sizeof(b));
                memset(e,0,sizeof(e));
                for(i=1; i<=n; i++)
                    scanf("%d %d",&a[i],&b[i]);
                init();
                int k=0;
                for(i=1; i<n; i++)
                {
                    for(j=i+1; j<=n; j++)
                    {
                        double s=ss(i,j);
                        if(s>=10.0&&s<=1000.0)
                        {
                            dd[k].x=i;
                            dd[k].y=j;
                            dd[k++].w=s;
                        }
                    }
                }
                sort(dd,dd+k,cmp1);
    
                double sum=0;
                int countt=0;
    
                for(i=0; i<=k-1; i++)
                {
                    if(merge(dd[i].x,dd[i].y)!=0)
                    {
                        countt++;
                        sum=sum+dd[i].w;
                    }
                    if(countt==n-1)
                        break;
                }
    
                if(countt==n-1)
                    printf("%.1lf\n",sum*100);
                else
                    printf("oh!\n");
            }
        }
    }
    

    HDU1879-继续畅通工程

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    using namespace std;
    
    #define inf 0x3f3f3f3f
    
    int m,n,f[110];
    
    struct E
    {
        int a;
        int b;
        int c;
        int d;
    }e[5000];
    
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
        }
    }
    
    int getf(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=getf(f[x]);
    }
    
    int merge(int x,int y)
    {
        int t1=getf(x);
        int t2=getf(y);
        if(t1!=t2)
        {
            f[t2]=t1;
            return 1;
        }
        return 0;
    }
    
    int cmp1(E x,E y)
    {
        if(x.d!=y.d)
            return x.d>y.d;//已建的排前面
        else
            return x.c<y.c;//否则按成本排
    }
    
    int main()
    {
        int i;
        while(~scanf("%d",&n)&&n)
        {
            init();
            for(i=1;i<=n*(n-1)/2;i++)
            {
                scanf("%d %d %d %d",&e[i].a,&e[i].b,&e[i].c,&e[i].d);
    //            if(e[i].d)
    //            {
    //                e[i].c=0;
    //            }
            }
            sort(e+1,e+n*(n-1)/2+1,cmp1);
            for(i=1;i<=n*(n-1)/2;i++)
            {
                //把边修好的合并在一起
                //没修的边按成本从小到大排
                if(e[i].d==1)//已建
                {
                    merge(e[i].a,e[i].b);
                }
            }
            int ans=0,countt=0;
            for(i=1;i<=n;i++)
            {
                if(f[i]==i)
                    ans++;
            }
            if(ans==1)
            {
                printf("0\n");
                continue;
            }
    
            int sum=0;
            for(i=1;i<=n*(n-1)/2;i++)
            {
                if(merge(e[i].a,e[i].b)!=0)
                //if(e[i].d==0)这里错了第一次写的时候
                {
                    countt++;
                    sum=sum+e[i].c;
                }//这题数据有点水,应该再合并一次,但这题也过了
                if(countt==ans-1)
                    break;
            }
            printf("%d\n",sum);
        }
        return 0;
    }
    
  • 相关阅读:
    2022春季 哈工大 硕士算法设计与分析 实验一分治算法
    2022 春季 硕士 算法设计与分析 作业
    Ubuntu18.04 没有有线网图标 可以连接wifi
    2022春季 哈工大 硕士算法设计与分析 实验二 搜索算法
    将博客搬至CSDN
    【面向对象课】作业Inherit
    [面向对象课]第二周上机
    CFA 金融工程 2.利用期货的对冲策略
    CFA 金融工程 1.导论:看涨看跌期权/多空头;积木分析法
    移动应用程序开发5 vue
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12650090.html
Copyright © 2020-2023  润新知