• hdu 4009 最小树形图模板题朱刘算法


    #include<stdio.h>
    /*思路:显然对于每个地方,
    只有一种供水方式就足够了,这样也能保证花费最小,
    而每个地方都可以自己挖井,所以是不可能出现无解的情况的,
    为了方便思考,我们引入一个虚拟点,把所有自己挖井的都连到这个点,
    边权为挖井的花费,而如果i能从j处引水,则从j向i连边,边权为引水的花费,
    然后对这个有向图,以虚拟点为根,求最小树形图即可(最小树形图即为有向图的最小生成树)。*/
    #include<string.h>
    #include<math.h>
    #include<stdlib.h>
    #define N 1100
    #define inf 999999999
    struct node {
    int x,y,z;
    }f[N];
    int n;
    struct nodee{
    int u,v,w;
    }edge[N*N];
    int manhadun(int x,int y) {
    return abs(f[x].x-f[y].x)+abs(f[x].y-f[y].y)+abs(f[x].z-f[y].z);
    }
    int yong,visit[N],pre[N],fffma[N],id[N];
    void addedge(int u,int v,int w) {
        edge[yong].u=u;
        edge[yong].v=v;
        edge[yong++].w=w;
    }
    int zhuliu(int root) {
      int sum=0,i;
      while(1) {
          for(i=0;i<=n;i++)
            fffma[i]=inf;
            memset(visit,-1,sizeof(visit));
            memset(id,-1,sizeof(id));
            for(i=0;i<yong;i++){
            int u=edge[i].u,v=edge[i].v;
            if(edge[i].w<fffma[v]&&u!=v) {//求所有除根节点外的点,选择一天最小权值的边
                pre[v]=u;//记录前驱
            fffma[v]=edge[i].w;
            }
            }
            fffma[root]=0;
            pre[root]=root;
            for(i=0;i<=n;i++){//若有孤立点则无解
                if(fffma[i]==inf)return -1;
            sum+=fffma[i];
            }
            int res=0;
            for(i=0;i<=n;i++)//所选择的边有没有环和环的个数
            if(visit[i]==-1) {
                    int v=i;
                while(visit[v]!=i&&id[v]==-1) {//这个地方需要注意
                    visit[v]=i;
                    v=pre[v];
                } 
                if(visit[v]!=i||v==root)continue;
                    int u;
                for(u=pre[v];u!=v;u=pre[u])
                    id[u]=res;
                id[v]=res++;
            }
            if(res==0)  return sum;//如果无环,则直接返回解
            for(i=0;i<=n;i++)//将环外的点都加入
                if(id[i]==-1)
                id[i]=res++;
            for(i=0;i<yong;i++) {//缩点出边不变,入边变
                edge[i].w-=fffma[edge[i].v];
                edge[i].u=id[edge[i].u];
                edge[i].v=id[edge[i].v];
            }
            n=res-1;root=id[root];//相当于建立了一个新图,root也会改变
      }
      return sum;
    }
    int main() {
      int i,j,k,x,y,z;
      while(scanf("%d%d%d%d",&n,&x,&y,&z),n||x||y||z) {
            yong=0;
        for(i=1;i<=n;i++) {
                scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z);
            addedge(0,i,f[i].z*x);//构造的虚拟点0为根节点,权值为每家建井的费用
        }
        for(i=1;i<=n;i++) {
            scanf("%d",&k);
            while(k--) {
                scanf("%d",&j);
                if(j==i)continue;
                if(f[j].z>f[i].z)
                    addedge(i,j,manhadun(i,j)*y+z);
                else
                    addedge(i,j,manhadun(i,j)*y);
            }
        }
        printf("%d
    ",zhuliu(0));
      }
    return 0;
    }

  • 相关阅读:
    Qt中的多线程编程
    c#实现内存映射文件共享内存
    Visual Studio 2019 使用C语言创建动态链接库(Dll)并使用C语言和C#实现调用
    Qt中子窗口关闭之后,立即释放资源的方法
    qt 定义插件
    UWP C# 调用 C++/CX
    Fedora Core 11 Alpha试用视频(由于youtube问题暂时无法访问)
    Linux下截图技巧
    使用无线局域网(WLAN)更需要注意加强安全防范
    Linux系统下到哪儿寻找硬件错误
  • 原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410706.html
Copyright © 2020-2023  润新知