中心捧月杯初赛--网络中两点之间的路径--完整答案篇

该题目的实质是求任意两点之间的最短路径(主路径),然后再分别根据两个约束条件求出备用路径,但关键是5000个节点的大数据处理起来就有点麻烦了。

下面是我自己做的答案,经过几组数据测试,在数据节点500以内时可以较短时间算出正确结果,也没有提示内存不足问题;但是当用5000节点数据时则会出现内存不足的问题而最终导致程序崩溃,希望精通算法和数据结构以及性能的优化的大神指出其中可优化的地方。下面是我的完整答案:

我的整体设计思路如下:

1,读取txt文件数据,并在此过程中格式化处理包括从第二行开始读取、节点排序,去除重复节点,并保存在数组里。

2,格式化读取数组,即获取连接的边和对应节点;再根据节点和构成邻接矩阵。

3,根据输入的源节点和目的节点,采取深度优先遍历,找出所有的源节点到目的节点的可达路径,并保存在vector中

4,过滤vector中的数据,求出最短路径(主路径)

5,根据两个约束条件,再次过滤vector中的数据,并保存在新的vector中

6,分别过滤两个约束条件的vector,找出其中最短路径,也就是备用路径

#include "stdafx.h"
#include <iostream>
#include <sstream> 
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>


using namespace std;

#define MAX_VEX_NUM 5001  //最大顶点数
#define weight 1          //弧的权值 
vector<string> allPath;   //向量,用来存放所有的顶点a到顶点i的路径
vector<int> all;          //向量,用来存放对应路径的长度
vector<int> ivec;         //存放临时数组
vector<int> vec;
vector<string> Path;
const int MAX=5001;
int num[MAX];
const int MAX1=11234;
int num1[MAX1];
const int MAX2=5001;
int num2[MAX2];

/*定义无向图的结构体*/
struct MGraph 
{
	int vexs[MAX_VEX_NUM];//顶点信息
    int arcs[MAX_VEX_NUM][MAX_VEX_NUM];//邻接矩阵
	int vexnum,arcnum;//顶点数和边数
};
MGraph G; //申明一个无向图的邻接矩阵类型

/* 图的基本操作,寻找V的位置*/
int Locatevex(MGraph G, int v)
{
	int i=0;
	while(i<G.vexnum && v!=G.vexs[i])// G.vexnum表示总顶点数,G.vexs[i]顶点值a,b,c。。。用来确定是那个顶点
		i++;//找不到时,i自加
	if(i<G.vexnum)
		return i;//查找成功则返回顶点的下标,即顶点值所对应的下标
	else
		return -1;//返回没有找到
}

/*数组邻接矩阵表示法构造无向图*/
int CreateUDG(MGraph &G,int a,int b,int num2[],int num1[]) 
{
	int v1,v2;
	cout<<"正在获取节点数和连接数....."<<endl;
    G.vexnum=a;//节点数
    G.arcnum=b;//连接数

	cout<<"正在获取节点值....."<<endl;
	for(int i=0;i<G.vexnum;i++)
		G.vexs[i]=num2[i];//节点值

	//初始化邻接矩阵
    for(int q=0;q<G.vexnum;q++)
	 for(int p=0;p<G.vexnum;p++)
		 G.arcs[q][p]=0;

	//构造邻接矩阵,弧数的2倍
	 for(int k=0;k<2*G.arcnum;k++)
	 {
		 v1=num1[k++];
		 v2=num1[k];
		 int a=Locatevex(G,v1);
		 int b=Locatevex(G,v2);
		 G.arcs[a][b]=weight;
		 G.arcs[b][a]=G.arcs[a][b];
	 }
	 cout<<"初始化邻接矩阵...."<<endl;
	 /*
	  for(int n=0;n<G.vexnum;n++)//输出顶点
		  cout<<G.vexs[n]<<" ";
	  cout<<endl;
	  cout<<"该图的邻接矩阵表示为...."<<endl;
	  for(int x=0;x<G.vexnum;x++)//输出邻接矩阵   G.vexnum指的是顶点个数
	  {
		 for(int y=0;y<G.vexnum;y++)  //两个for循环,G.vexnum指的是顶点个数
		 {
			 cout<<G.arcs[x][y]<<" ";//一个值和一个空格
		 }
		 cout<<endl;//最后一行有空格
	  }
	  cout<<endl;
	  */
      return 1;
}  

/*递归获取所有节点va到节点vb的路径*/
void Minway(MGraph G,bool *visited,int vexs,int Long,int vb,string path)   {
	if (vexs==vb)     //递归结束条件,即寻找到结束点
	{
		stringstream ss;      //数字转换为字符串
	    ss<<vexs;
	    path=path+" "+ss.str();        //存放路径的字符串,vexs指的是顶点值
		allPath.push_back(path);    //将路径放入向量中,存放路径
		all.push_back(Long);       //将路径长放入对应向量中,存放长度
		cout<<"路径:"<<path<<"  长度:"<<Long<<endl;
	}
	else
	{
		 stringstream ss;      //数字转换为字符串
	     ss<<vexs;
	     path=path+" "+ss.str();        //存放路径的字符串
     	int i=Locatevex(G,vexs);//返回定点的下标值,即获取下一节点
    	visited[i]=true;  //标识该点被访问过
	    for(int j=0;j<G.vexnum;j++) //遍历该点到下一点的所有可达点
		{   
	    	if((!visited[j])&&(G.arcs[i][j]!=0)) //如果下一点满足未被访问过且连接
	    	{	
				cout<<"寻到"<<j<<"正处理....."<<endl;
		    	Minway(G,visited,G.vexs[j],Long+G.arcs[i][j],vb,path);  //递归调用自身
	    	}
		}
		visited[i]=false;       //退出递归前清除访问记录
	}
}
/*调用递归函数来实现递归求取所有可达路径*/
void CountMinway(MGraph G,int va, int vb)          
{
	string path;                //存放路径
	int i=Locatevex(G,va);
	bool visited[501];//布尔型数组,确定是否被访问过
	for(int j=0;j<G.vexnum;j++)
		visited[j]=false;             //初始化访问记录,全都未访问过
	visited[i]=true;                  //起点顶点设为访问过
	int Long=0;           //初始化路径长度为0  
	stringstream ss;      //整形为字符串
	ss<<va;
	path+=ss.str();            //记录访问过的路径
	for(int j=0;j<G.vexnum;j++)//逐个遍历其他节点
	{
		if(G.arcs[i][j]!=0)//如果相连
		{   
			cout<<"起点存在邻接点:"<<j<<endl;
			Long=G.arcs[i][j];//增加长度
			Minway(G,visited,G.vexs[j],Long,vb,path); //调用递归部分
		}
	}
	cout<<endl;
}
/*输出最短路径和备用路径*/
void Minway(int va, int vb)
{
	int min=168,j,temp;
	for(int i=0;i < allPath.size();i++)//找到最小路径的长度
	{
		if(all[i]<min)
			min=all[i];
	}
	for(j=0;j<allPath.size();j++)//找到与最小路径长度匹配的路径
	{
		if(all[j]==min)
		{
			cout<<"主路径:  "<<allPath[j]<<endl;
			stringstream s(allPath[j]);
	        while(s>>temp)
		    {
			vec.push_back(temp);
		    }
			break;
		}

	}
	int backnum[128];
	int p;
	cout<<"请输入备用路径的的约束条件1或2:"<<endl;
	cin>>p;
	switch(p)
	{
	case 1:
		for(vector < string >::iterator st=allPath.begin();st!=allPath.end();++st)
		{
			stringstream ss( *st );
			while(ss>>temp)
			{
				ivec.push_back(temp);
			}
			bool c=false;
			for(vector < int >::iterator it=ivec.begin();it!=ivec.end();++it)
			{
				for(vector < int >::iterator t=vec.begin();t!=vec.end();++t)
				{
					if((*t)==(*it)&&((*t)!=va||(*t)!=vb))
					{
					 c=true;
					}

				}	
			}
			if(!c&&(st!=allPath.end()))
			{
            Path.push_back(*st);
			}
			
		}
		break;
	case 2:
		for(vector < string >::iterator st=allPath.begin();st!=allPath.end();st++)
		{
			stringstream ss( *st );
			while(ss>>temp)
			{
				ivec.push_back(temp);
			}
			bool c=false;
			int k=65530;
			for(vector < int >::iterator it=ivec.begin();it!=ivec.end();++it)
			{
				for(vector < int >::iterator t=vec.begin();t!=vec.end();++t)
				{
					k--;
						if((*it)==(*t))
						{
							if(k==0)
							{
                             c=true;
							}
						 k=vec.size()+1;
						}
				}
			}
			if(!c&&(st!=allPath.end()))
			{
            Path.push_back(*st);
			}
		}
		break;
	default:
		cout<<"您输入的约束条件有误!"<<endl;
		break;
	}

	min=168;
	if(Path.size())
	{
	for(int i=0;i<Path.size();i++)//找到约束条件所有路径的长度
	{
		if(all[i]<min)
			min=all[i];
	}

	for(j=0;j<Path.size();j++)//找到与次优路径长度匹配的路径
	{
		if(all[j]==min)
			cout<<"备用路径:  "<<Path[j]<<endl;
	}
	}
	else
	{
     cout<<"找不到该约束条件下的备用可达路径!"<<endl;
	 return;
	}
	cout<<endl;
}


int main(int argc, char* argv[])
{ 
	ifstream fin("Bigdata1.txt"); 
	if(!fin )
	{  
      cerr << "Error opening file";    
         exit(EXIT_FAILURE);    
    }     
    const int cnt = 2;  
    string s; 
    int q=0,head=0,m=0,n=0,j=0,i=0,p=0;
    size_t comma = 0;
    size_t comma2 = 0;
    while( getline(fin,s) )
    {  
		if(head==0)
		{
			//跳过第一行的表头
			head=1;
			continue;
         }
		q++;
        cout << "Read from file: " << s << q <<endl;
		comma = s.find(',',0); 
		m = atoi(s.substr(0,comma).c_str()); 
		num1[i]=m;
		cout<<m<<' '<<i<<' '<<num1[i]<<' ';
		i++;
		while (comma < s.size() && j != cnt-1) 
        { 
            comma2 = s.find(',',comma + 1); 
            m= atoi(s.substr(comma + 1,comma2-comma-1).c_str()); 
			num1[i]=m;
           cout<<m<<' '<<i<<' '<<num1[i]<<' '; 
		   i++;
           ++j; 
            comma = comma2; 
        }         
        cout<<endl; 
        j = 0; 
    }
	fin.close();
	n=2*q;
	for (int c =0; c< 2*q; ++c) {   //for循环接收输入,并进行判断,实现去重  
		num[0]=num1[c];             //将数据输入到num[0]
		if (num[num[0]] == 1) {   //判断num[*]==0
			n--;                  //n自减1
			continue;           
		}             
		num[num[0]]=1;    
	}   
	int t=n;
	cout<<n<<endl;  
	for (int c =1; c< MAX ;++c) {     
		if (num[c] == 0) {               
			continue;          
		}            
		n--; 
		num2[p]=c;
		p++;
		cout<<c;        
		if (n!=0) cout<<" ";   
		else cout<<endl;       
	}   
    CreateUDG(G,t,q,num2,num1);  //构建无向图
	int va,vb;
	cout<<"请输入源节点"<<endl;
    cin>>va;
	cout<<"请输入目的节点"<<endl;
	cin>>vb;
	CountMinway(G,va,vb);             //找出所有可达路径
	Minway(va,vb);      //输出最短路径和备用路径
	return 0;
}


 

你可能感兴趣的:(中心捧月杯初赛--网络中两点之间的路径--完整答案篇)