HDU 1863

来源:互联网 发布:yap—yum示意图 编辑:程序博客网 时间:2024/05/16 12:13

       这是一道最小生成树的题目,很适合刚学完Prim算法或Kruskal算法的人来练手。

       Prim算法:首先,把图中的顶点集分成Va和Vb两个集合,Va中的点属于最小生成树,Vb中的点属于待选的点。起初,Va中只有一个点,这个点是任意选择的。两个集合间存在相互连接的边,选择其中权值最小的边,并把对应的点加入集合Va中,重复上述选择过程,直到无边可选。如果Vb中没有点,则说明图G存在最小生成树,否则图G不存在最小生成树。

      Kruskal算法:每次选择图中权值最小,但又不会与已选择的边构成环的边,直到无边可选,如果选择的边数为n-1(假设图的顶点数为n),那么图G存在最小生成树,否则图G不存在最小生成树。

      再说详细点,在用Prim算法时,我用了链式前向星来保存图,判断两个集合间的权值最小的边时,我用了优先队列,这样比单纯用二维数组更快(不过我没正的对比过)。在用Kruskal算法时,我用了前向星来存图,用并查集来判断所选的边是否与已存在的边构成环。(关于链式前向星和前向星的讲解可以参考《ACM—ICPC程序设计系列 图论及应用》(哈尔滨工业大学出版社)第一章)


代码(G++):

Prim算法:

#include <cstdlib>#include <iostream>#include <queue>#define MAXp 105#define MAXe 9900using namespace std;int vis[MAXp],head[MAXp],m;  //true表示属于生成树的点集,false表示不属于 struct edge{     int to;    int next;    int w;  };edge array[MAXe*2];struct cmp{    bool operator() (int a,int b)    {         return array[a].w>array[b].w;    }};priority_queue<int,vector<int>,cmp> pq;void prim(int u,int &ans,int &amount){     if(amount==m) return;     int i,tmp,v;     for(i=head[u];i!=-1;i=array[i].next) pq.push(i);      while(!pq.empty())     {        tmp=pq.top();        pq.pop();                v=array[tmp].to;        if(!vis[v])        {           ans+=array[tmp].w;           vis[v]=true;           amount++;           prim(v,ans,amount);           break;        }     }                  }int main(int argc, char *argv[]){    int n,i,u,v,w,c,ans,amount;        while(scanf("%d %d",&n,&m)&&n!=0)    {        memset(vis,false,sizeof(vis));        memset(head,-1,sizeof(head));        c=ans=0;                    for(i=0;i<n;i++)        {            scanf("%d %d %d",&u,&v,&w);            array[c].to=v;            array[c].w=w;            array[c].next=head[u];            head[u]=c;            c++;            array[c].to=u;            array[c].w=w;            array[c].next=head[v];            head[v]=c;            c++;        }        vis[1]=true;        amount=1;        prim(1,ans,amount);        while(!pq.empty()) pq.pop();                                if(amount<m) printf("?\n");         else printf("%d\n",ans);          }    system("PAUSE");    return EXIT_SUCCESS;}

Kruskal算法:

#include <cstdlib>#include <iostream>#include <algorithm>#define MAXe 9900#define MAXp 100using namespace std;struct edge{    int u;    int v;    int w;   };edge array[MAXe];int fa[MAXp];bool cmp(edge a,edge b){     if(a.w!=b.w) return a.w<b.w;          if(a.u!=b.u) return a.u<b.u;                          return a.v<b.v;                          }int find(int a){    if(fa[a]!=a) fa[a]=find(fa[a]);                    return fa[a];}int main(int argc, char *argv[]){    int n,m,i,u,v,w,c,ans,amount,p,fu,fv;    while(scanf("%d %d",&n,&m)&&n!=0)    {        c=0;                    for(i=0;i<n;i++)        {            scanf("%d %d %d",&u,&v,&w);            array[c].u=u;            array[c].v=v;            array[c].w=w;            c++;        }        sort(array,array+c,cmp);          for(i=1;i<=m;i++) fa[i]=i;         ans=amount=p=0;                for(i=1;i<m;i++)        {            while(p<c)            {               fu=find(array[p].u);               fv=find(array[p].v);               if(fu!=fv)               {                  fa[fu]=fv;                  ans+=array[p].w;                  amount++;                  break;               }               p++;              }                 }                 if(amount==m-1) printf("%d\n",ans);        else printf("?\n");           }    system("PAUSE");    return EXIT_SUCCESS;}


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

畅通工程

                                                                              Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N 
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
 

Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
 

Sample Input
3 31 2 11 3 22 3 41 32 3 20 100
 

Sample Output
3?


               

0 0
原创粉丝点击