• poj 1639 Picnic Planning 夜


    http://poj.org/problem?id=1639

    最小限制生成树 黑书上有 推荐 我看了上面的解析自己闷头写了一个 不好 我自己看着都乱 唉就这样吧

    大体就是 先求出除了关键点以外的点形成的若干最小生成树  然后把这些最小生成树和关键点用最短的距离联系起来

    然后不断点加与关键点之间的的连线 每联一个就会多一个环 然后就得删一个边  把环取消 不过加的边 和删的边的选取必须是加边减去删边的

    值最小   一旦限度达到 或者更新后不如原来的小了 则放弃更新

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<queue>
    #include<map>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int N=101;
    const int M=10000;
    struct node
    {
        int k;
        struct tt *next;
    }mem[N];//邻接表头  k 表示到此点到基本点的边中 不和基本点相连的边中最长的边
    struct tt
    {
        int wside;
        struct tt *next;
        int j;
    };//wside 代表哪条边
    struct lin
    {
        int x,y;
        int dist;
    }linkside[M];//记录边的两端 和距离
    int have[M];//此条边的状态 1 表示最图中 -1 表示删掉不再用 0表示待定
    int f[N];//最小生成树中的最终父节点  和dfs是标记是否搜过那个点
    int m,k,limit,n;//m为边的个数 n为点的个数 limit为限度 k和基本点相连的度
    map<string,int>str;
    int MIN,V0;//在限制的情况下最小树  和基本点
    int findx(int x)//你懂得
    {
        if(f[x]!=x)
        f[x]=findx(f[x]);
        return f[x];
    }
    bool cmp(lin a,lin b)
    {
        return a.dist<b.dist;
    }
    void build(int ,int ,int );
    void prim()
    {
        sort(linkside,linkside+m,cmp);
        memset(have,0,sizeof(have));
        for(int i=0;i<n;++i)
        f[i]=i;
        for(int i=0;i<m;++i)
        {
            int l1=linkside[i].x,l2=linkside[i].y;
            if(findx(l1)==findx(l2))//如果有环 此边不要
            {
                have[i]=-1;
                continue;
            }
            if(l1!=V0&&l2!=V0)//不是有基本点的边
            {
                have[i]=1;//记录边状态
                MIN+=linkside[i].dist;//增加全局变量
                f[findx(l1)]=l2;
                build(l1,l2,i);//建树
                build(l2,l1,i);
            }else
            {
                if(l1==V0)//如果为基本点相连的边 建树但不记录
                build(l1,l2,i);
                else
                build(l2,l1,i);
            }
        }
    }
    void build(int i,int j,int l)
    {
        struct tt *t=new tt;
        t->j=j;
        t->wside=l;
        t->next=mem[i].next;
        mem[i].next=t;
    }
    void Dele(int n)
    {
        struct tt *t;
        for(int i=0;i<=n;++i)
        {
            while(mem[i].next!=NULL)
            {
                t=mem[i].next;
                mem[i].next=t->next;
                delete (t);
            }
        }
    }
    void dfs(int x,int k)
    {
        f[x]=1;
        mem[x].k=k;//更新到此点为止最长边(不含和基本点相连的)
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(!f[t->j]&&have[t->wside]==1)
            {
                int down=(linkside[k].dist<linkside[t->wside].dist)?t->wside:k;//选择较长的向下更新
                dfs(t->j,down);
            }
            t=t->next;
        }
    }
    void update()
    {
        memset(f,0,sizeof(f));
        f[V0]=1;
        struct tt *t=mem[V0].next;
        while(t!=NULL)
        {
            if(have[t->wside]==1)
            {
                dfs(t->j,m);//第m条边 已被定义为距离最小
            }
            t=t->next;
        }
    }
    int main()
    {
    
       //freopen("data.txt","r",stdin);
       string sstemp1,sstemp2,park="Park";
       while(scanf("%d",&m)!=EOF)
       {
           str.clear();
           int I=0;
           V0=-1;
           for(int i=0;i<m;++i)
           {
               int l1,l2,d;
               cin>>sstemp1>>sstemp2>>d;
               if(str.find(sstemp1)==str.end())//用map 把字符串对应成数字
               {str[sstemp1]=I;l1=I++;}
               else
               l1=str[sstemp1];
               if(str.find(sstemp2)==str.end())
               {str[sstemp2]=I;l2=I++;}
               else
               l2=str[sstemp2];
               linkside[i].x=l1;
               linkside[i].y=l2;
               linkside[i].dist=d;
               if(V0==-1)//记录基本点
               {
                   if(sstemp1==park)
                   V0=l1;
                   if(sstemp2==park)
                   V0=l2;
               }
           }
           n=I;
           scanf("%d",&limit);
           MIN=0;
           prim();//建立除了基本点以外的若干 最小生成树
           linkside[m].dist=-1;
           k=0;
           for(int i=0;i<m;++i)
           {
               if(have[i]!=0)
               continue;
               int l1=linkside[i].x,l2=linkside[i].y;
               if(findx(l1)==findx(l2))
               continue;
               if(l1==V0)//对和基本点相连的边进行选最小的更新 但不能形成环 做相应的记录
               {
                   have[i]=1;
                   f[findx(l1)]=l2;
                   ++k;
                   MIN+=linkside[i].dist;
               }
               if(l2==V0)
               {
                   have[i]=1;
                   f[findx(l1)]=l2;
                   ++k;
                   MIN+=linkside[i].dist;
               }
           }
           update();//更新每个点到基本点的边中最长的(不含和基本点直接相连的)
           for(;k<limit;++k)
           {
               int wtemp=-1,ktemp,mitemp;
               struct tt *t=mem[V0].next;
               while(t!=NULL)
               {
                   if(have[t->wside]==0)//选新的和基本点相连的点
                   {
                       if(wtemp==-1||linkside[t->wside].dist-linkside[mem[t->j].k].dist<mitemp)
                       {
                           wtemp=t->wside;
                           mitemp=linkside[t->wside].dist-linkside[mem[t->j].k].dist;
                           ktemp=mem[t->j].k;
                       }
                   }
                   t=t->next;
               }
               if(wtemp==-1||mitemp>=0)//如果没选到 或者更新后无法跟新最终答案 则没有必要继续更新
               {
                   break;
               }
               have[wtemp]=1;
               have[ktemp]=-1;
               MIN+=mitemp;
               update();
           }
           printf("Total miles driven: %d\n",MIN);
           Dele(n);
       }
       return 0;
    }
    

      

  • 相关阅读:
    memento模式
    observe模式
    state模式
    Trie树的简单介绍和应用
    strategy模式
    全组和问题
    SRM 551 DIV2
    全排列问题
    TSE中关于分词的算法的改写最少切分
    template模式
  • 原文地址:https://www.cnblogs.com/liulangye/p/2623421.html
Copyright © 2020-2023  润新知