奥运场馆规划问题(数据结构解决)

问题描述:

 1、在奥运场馆选址初期,规划师已经保证了所有场馆之间都有直接或者间接的道路相连接。但是往往事与愿违,奥运会期间巨大的交通压力将使得部分道路变得格外的拥堵。如果两个场馆之间的平均车速在每小时20公里以下(<20),则认为该两点之间的道路为不可以通行。那么现在有游客想驾车游览所有的奥运场馆,假设游览一次意味着可以把所有能够通行的场馆全部参观完,请问。 (1)根据给出的各条道路的数据确定参观完所有场馆需要分几次进行? (2)按照每次能够参观的场馆数从多到少的顺序分别给出各次所能参观的场馆数,且从小到大依次输出每次参观的场馆编号。

 2、为了满足奥运期间新闻报道的需要,场馆间计划铺设光纤来传输新闻信号。假设光纤必须沿着道路铺设,不管该道路的平均车速是否超过20公里都可以用来铺设光纤,消耗光纤长度与道路长度相等。为了节省资源,希望尽可能减少总的光纤使用量。请根据场馆间所有道路(包括平均车速在20公里以下的)分布情况设计最优的光纤铺设方案。 3、鉴于场馆间的平均车速在每小时20公里以下(<20)的道路由于过分拥堵被认为是不可以通行的。场馆规划小组计划把这些地面拥堵道路中的部分路线改造为地下道路来连通所有的场馆,使得所有场馆之间都可以直接或间接到达,这样游客驾车游览一次就可以把所有的场馆都参观完。假设改造后原有的地上道路改为步行街不再允许机动车通行,所有的地下道路均畅通无阻。请以所给的地面道路数据为依据,设计一个最经济(即被改造道路的总长度最短)的地下道路的建造方案。

 算法思路:

奥运场馆间的道路长度和车速之间应该用带权图来表示,而这里的权值应该包括两个——道路长度和场馆之间的车速。 l         图的建立   采用邻接矩阵的方式建立一个带权图,在该程序里采用了一个表示图的邻接矩阵的结构体,一个表示两个权值的结构体来描述图。 l         问题1的解决方案 1.       第一小问属于非连通图的遍历问题:图的遍历采用一个递归方式表示的图的深度优先遍历;由于场馆才满足如果平均车速在每小时20公里以下就表示两点之间不可通行,那么该图是一个非连通图,为了访问到图中的所有结点,以图中未被访问到的每一个顶点为初始点,去调用上面的遍历算法: For(int i=0;i<n;i++)    If(!visited[i])dfs1(ga,I,n); 有多少次调用就表示有多少个连通分量,有多少个连通分量就表示要参观完所有的场馆需要分几次进行。 2.       第二小问采用顺序表的方法来保存各次能参观的场馆编号,为了能够按从多到少给出所能参观的场馆,还应该采用一个排序算法对顺序表里的元素(即各个连通的场馆)进行排序。 l         问题2的解决方案问题2是典型的Prim算法求最小生成树的问题,只要调用一个Prim算法,就可以求出最有的光线铺设方案。 l         问题3的解决方案问题3的解决要略于复杂一些。利用问题1求出的各个连通分量,只要各个连通分量之间连通后,则整个图就连通了。然后求出各个连通分量之间的满足条件的最短路径(即在道路地面部分拥堵),这时需要记下各个最短路径之间的两个顶点编号;要求出最经济的地下道路建设方案,首先要满足图之间要连通,这样问题就变成了另一个求最小生成树的问题,这里的图中各个顶点为各个连通分量,图的权值为连通分量之间的最短路径。再次调用Prim就可以求出连通分量之间的最小生成树,继而就求出了最经济的地下道路建设方案。为了形象地描述解决方案。

代码:  

#include<iostream> #include<fstream> #include<stdlib.h>

using namespace std; //建立图的存储结构,用邻接矩阵表示,带两个权值,所以用一个结构体来表示

const int MaxVerterxNum=7; const int MaxValue=1000; const int MaxSizelist=20;

//为保存每次能够参观的场馆从多到少的顺序,设立一个线性表来保存数据 struct SeqList {  int *list;  int len;  int MaxSizelist; }; void InitList(SeqList &L) {  L.list=new int[MaxSizelist];  if(L.list==NULL)  {   cerr<<"Memory allocation failure!"<<endl;   exit(1);  }  L.len=0; } void insertList(SeqList &L,int item) {  if(L.len==MaxSizelist)  {   cout<<"overflow!"<<endl;   exit(1);  }  //static int i=0;  //L.list[i]=item;  //i++;  //L.len++;  for(int j=L.len-1;j>=0;j--)L.list[j+1]=L.list[j];  L.list[0]=item;  L.len++; } //这里再做一张小图来解决问题3

struct mNode {  int mweight;  int a;  int b; }; struct mGraph {  int Vcnt;  mNode *madj;

};

   

 

struct Node {  int length,speed; }; struct Graph                                              //建立图结构 {  //Node *node;  int Vcnt;  Node *adj;//MODIFIED HERE  bool *visited; }; void initmGraph(mGraph &mGA,int v) {  mGA.Vcnt=v;  mGA.madj=new mNode[v*v];  for(int i=0;i<v;i++)  {   for(int j=0;j<v;j++)    mGA.madj[i*v+j].mweight=1001;  } }

void initGraph(Graph &GA,int v)                           //对图进行初始化 {  GA.Vcnt=v;  //GA.adj=new int [v*v];  GA.adj=new Node[v*v];  GA.visited=new bool[v];  for(int i=0;i<v;i++)  {   for(int j=0;j<v;j++)   {    if(i==j){GA.adj[i*v+j].length=0;GA.adj[i*v+j].speed=0;}    else GA.adj[i*v+j].length=MaxValue;GA.adj[i*v+j].speed=0;   }   GA.visited[i]=false;  } }

void dfs1(Graph &GA,int i,SeqList &L)                                //递归算法对图进行深度优先遍历(待完善) {    //cout<<i<<' ';  GA.visited[i]=true;  insertList(L,i);  for(int j=0;j<GA.Vcnt;j++)//What is 'n'?to be modified   if(GA.adj[i*GA.Vcnt+j].length!=0&&GA.adj[i*GA.Vcnt+j].length!=MaxValue&&GA.adj[i*GA.Vcnt+j].speed>20&&!GA.visited[j])dfs1(GA,j,L); } //排序算法 void order(SeqList &L,int n) {  int i,j;  for(i=0;i<n;i++)  {   for(j=n-1;j>i;j--)   {    if(L.list[j-1]>L.list[j])    {     int temp=L.list[j-1];     L.list[j-1]=L.list[j];     L.list[j]=temp;    }   }  } }

//边集数组 struct edge {  int fromvex;  int endvex;  int weight; }; //from v求最小生成树 void Prim(Graph &GA,edge *mst,int v) {

     for(int i=0;i<GA.Vcnt;i++)  {   if(i<v)   {    mst[i].fromvex=v;    mst[i].endvex=i;    mst[i].weight=GA.adj[v*GA.Vcnt+i].length;   }   else if(i>v)   {    mst[i-1].fromvex=v;    mst[i-1].endvex=i;    mst[i-1].weight=GA.adj[v*GA.Vcnt+i].length;   }  }    for(int k=1;k<GA.Vcnt;k++)  {   int min=MaxValue;   int m=k-1;   for(int j=k-1;j<GA.Vcnt-1;j++)    if(mst[j].weight<min)    {     min=mst[j].weight;     m=j;    }           edge temp;    temp=mst[k-1];    mst[k-1]=mst[m];    mst[m]=temp;       j=mst[k-1].endvex;

   for(i=k;i<GA.Vcnt-1;i++)    {     int t=mst[i].endvex;//cout<<"j_____"<<j<<endl;     int w=GA.adj[j*GA.Vcnt+t].length;     if(w<mst[i].weight)     {      mst[i].weight=w;      mst[i].fromvex=j;           }    }  } }

//m边集数组 struct medge {  int fromvex;  int endvex;  int weight;  int ma;  int mb; }; void mPrim(mGraph &mGA,medge *mmst,int v) {

     for(int i=0;i<mGA.Vcnt;i++)  {   if(i<v)   {    mmst[i].fromvex=v;    mmst[i].endvex=i;    mmst[i].weight=mGA.madj[v*mGA.Vcnt+i].mweight;    mmst[i].ma=mGA.madj[v*mGA.Vcnt+i].a;    mmst[i].mb=mGA.madj[v*mGA.Vcnt+i].b;

  }   else if(i>v)   {    mmst[i-1].fromvex=v;    mmst[i-1].endvex=i;    mmst[i-1].weight=mGA.madj[v*mGA.Vcnt+i].mweight;    mmst[i-1].ma=mGA.madj[v*mGA.Vcnt+i].a;    mmst[i-1].mb=mGA.madj[v*mGA.Vcnt+i].b;   }  }    for(int k=1;k<mGA.Vcnt;k++)  {   int min=MaxValue;   int m=k-1;   for(int j=k-1;j<mGA.Vcnt-1;j++)    if(mmst[j].weight<min)    {     min=mmst[j].weight;     m=j;    }           medge temp;    temp=mmst[k-1];    mmst[k-1]=mmst[m];    mmst[m]=temp;       j=mmst[k-1].endvex;

   for(i=k;i<mGA.Vcnt-1;i++)    {     int t=mmst[i].endvex;//cout<<"j_____"<<j<<endl;     int w=mGA.madj[j*mGA.Vcnt+t].mweight;     int ja=mGA.madj[j*mGA.Vcnt+t].a;     int jb=mGA.madj[j*mGA.Vcnt+t].b;     if(w<mmst[i].weight)     {      mmst[i].weight=w;      mmst[i].fromvex=j;      mmst[i].ma=ja;      mmst[i].mb=jb;           }    }  } }

 

//主函数 main(int argc,char *argv[]) {  FILE *fp;  FILE *ofp;  int totalvex,a,b;  int i=0;  //int a1,b1;  int num1=0;//参观的次数  SeqList *sq;  int list=0;  edge *mst;  medge *mmst;  int totallength=0;//光纤的总长度  int totalroot=0;//修建的地下道路的总长度 // InitList(sq);

 Graph GA;//建立第一个大图      // Adjmatrix adjmatrix[MaxVerterxNum][MaxVerterxNum];  if((fp=fopen(argv[1],"r+"))==NULL)  {   cout<<"Cannot open this file!"<<endl;   exit(0);  }    fscanf(fp,"%d",&totalvex);

 initGraph(GA,totalvex);//初始化大图  fscanf(fp,"%d",&a);  while(a!=-1)  {            fscanf(fp,"%d",&b);          fscanf(fp,"%d",&(GA.adj[a*totalvex+b].length));               fscanf(fp,"%d",&(GA.adj[a*totalvex+b].speed));          GA.adj[b*totalvex+a]=GA.adj[a*totalvex+b];          fscanf(fp,"%d",&a);      }  fclose(fp);         /*for(int i=0;i<totalvex;i++) {  for(int j=0;j<totalvex;j++)       cout<<GA.adj[i*totalvex+j].length<<"       "<<GA.adj[i*totalvex+j].speed<<"   ";//<<endl;

}*/ //cout<<"a="<<a<<endl;/ //对第一问的存储路径进行初始化 sq=new SeqList[20]; for(int temp2=0;temp2<20;temp2++) {  InitList(sq[temp2]); }

//以下为计算参观完所有的场馆需要分几次进行 for(i=0;i<totalvex;i++) if(!GA.visited[i]){dfs1(GA,i,sq[num1]);num1=num1+1;} //for(i=0;i<num1;i++) //cout<<"sq["<<i<<"].len="<<sq[i].len<<' ';

/*for(i=0;i<num1;i++) {  for(int temp1=sq[i].len-1;temp1>=0;temp1--)  {     cout<<sq[i].list[temp1]<<' ';  }  cout<<endl;

}*/ //对sq里面的元素进行从小到大的排序,以满足题目要求 for(i=0;i<num1;i++) {  order(sq[i],sq[i].len); } //第二次输出验证 /*for(i=0;i<num1;i++) {  for(int temp1=0;temp1<sq[i].len;temp1++)  {     cout<<sq[i].list[temp1]<<' ';  }  cout<<endl;

}*/

//现在在sq[i].list[]里保存的就是第i次可以参观的场馆编号,num1就是参观完场馆需要的次数 //cout<<"num1="<<num1<<endl; if((ofp=fopen(argv[2],"w"))==NULL) {  cout<<"Cannot open this file!"<<endl;  exit(0); } //设定文件的输出格式 fputs("A",ofp); fputs("/n",ofp); fprintf(ofp,"%d",num1); fputs("/n",ofp); for(i=0;i<num1;i++) {  for(int temp1=0;temp1<sq[i].len;temp1++)  {   fprintf(ofp,"%d",sq[i].list[temp1]);   fputs(" ",ofp);  }  fputs("/n",ofp); } fputs("#",ofp); fputs("/n",ofp);

 

//现在mst中的数据就是铺设光纤道路的两个场馆之间的标号其中mst[].fromvex,mst[].endvex分别为起始点和终止点 //mst[].weight为需要的光纤长度,现在还没有计算总长度和需要的光纤数 mst=new edge[GA.Vcnt-1];//建立边集数组 Prim(GA,mst,0);

for(i=0;i<GA.Vcnt-1;i++) {  totallength=totallength+mst[i].weight;

 //cout<<mst[i].fromvex<<"-->"<<mst[i].endvex<<"  "<<mst[i].weight<<endl; } //cout<<"totallength"<<totallength<<endl; //将光纤的分布情况写入到文件output.txt fputs("B",ofp); fputs("/n",ofp); fprintf(ofp,"%d",GA.Vcnt-1); fputs(" ",ofp); fprintf(ofp,"%d",totallength); fputs("/n",ofp);

for(i=0;i<GA.Vcnt-1;i++) {  fprintf(ofp,"%d",mst[i].fromvex);fputs(" ",ofp);  fprintf(ofp,"%d",mst[i].endvex);fputs(" ",ofp);  fprintf(ofp,"%d",mst[i].weight);  fputs("/n",ofp); } fputs("#",ofp); fputs("/n",ofp);

  //现在是设计一个最经济的的地下道路建设方案,思路见本 //建立各个连通分量之间的符合条件的最短的铺设路径 int *min=new int[num1*num1]; for(i=0;i<num1*num1;i++) min[i]=MaxValue+1; int from[50][2]={0};//为了记下改造路线的结点号 //from={0}; for(i=0;i<num1;i++)//i,j连通分量之间的符合条件最短长度 {  for(int j=i+1;j<num1;j++)  {   for(int i1=0;i1<sq[i].len;i1++)   {    for(int i2=0;i2<sq[j].len;i2++)    {a=sq[i].list[i1];    b=sq[j].list[i2];    //cout<<"a b"<<a<<' '<<b<<endl;    if(GA.adj[a*GA.Vcnt+b].speed<20&&GA.adj[a*GA.Vcnt+b].length<MaxValue&&min[i*num1+j]>GA.adj[a*GA.Vcnt+b].length)    {     min[i*num1+j]=GA.adj[a*GA.Vcnt+b].length;     min[j*num1+i]=min[i*num1+j];     from[i*(num1-1)+j][0]=a;     from[i*(num1-1)+j][1]=b;//cout<<"~~~~~"<<endl;              }

   }   }  } }

//测试部分,i表示连通分量 //for(i=0;i<num1;i++) //{ // for(int j=0;j<num1;j++) //  cout<<i<<"->"<<j<<" "<<min[i*num1+j]<<" ;"; // cout<<endl; //} //果然要再做一张小图么 mGraph mGA; initmGraph(mGA,num1);

for(i=0;i<num1;i++) {  for(int j=0;j<num1;j++)  {   mGA.madj[i*num1+j].mweight=min[i*num1+j];   mGA.madj[j*num1+i].mweight=mGA.madj[i*num1+j].mweight;   mGA.madj[i*num1+j].a=from[i*(num1-1)+j][0];   mGA.madj[i*num1+j].b=from[i*(num1-1)+j][1];

 } }

mmst=new medge[mGA.Vcnt-1];//建立边集数组 mPrim(mGA,mmst,0); for(i=0;i<num1-1;i++) {  totalroot=totalroot+mmst[i].weight; //cout<<"from "<<mmst[i].ma<<"to "<<mmst[i].mb<<"--->weight "<<mmst[i].weight<<endl; } //将改造的道路信息写入到文件output.txt fputs("C",ofp); fputs("/n",ofp); fprintf(ofp,"%d",mGA.Vcnt-1);fputs(" ",ofp);fprintf(ofp,"%d",totalroot); fputs("/n",ofp); for(i=0;i<num1-1;i++) {  fprintf(ofp,"%d",mmst[i].ma);fputs(" ",ofp);  fprintf(ofp,"%d",mmst[i].mb);fputs(" ",ofp);  fprintf(ofp,"%d",mmst[i].weight);fputs("/n",ofp); } fputs("#",ofp);

//for(i=0;i<

 

fclose(ofp); cout<<"Successful!"<<endl; return 0;

}

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值