数据结构课程设计------景区管理系统

//
//  main.cpp
//  景区旅游信息管理系统
//
//  Created by 魏治鹏 on 2019/3/6.
//  Copyright © 2019 魏**. All rights reserved.
//


#include <iostream>
#include <algorithm>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#include <iomanip>
#include <bitset>
#include <fstream>
#include <sstream>
typedef long long int ll;
using namespace std;


#define INf 0x3f3f3f
#define maxN 10001
#define maxM 10001


typedef struct Linknode {
    string Name;
    struct Linknode  *next;
}LinkNode;

typedef struct TreeNode
{
    int count;
    TreeNode * next[26];
    int num;
    string introduction;
}TreeNode;

typedef struct Information{     //景点详细信息,实现随机查询,通过字典数返回的下标
    string Information;
}In;

typedef struct E{                    //边链结构体
    int u,v;
    int w ;
    struct E *next;
}Edge;

typedef struct e{                    //定义结构体堆的结构体
    int u,v,w;
}edge;

struct cmp
{
    bool operator()(const edge&a, const edge&b)  //对括号进行重载
    {
        return a.w > b.w;
    }
};

struct NetEdge
{
    int to,cap,rev;
    NetEdge(int to,int cap,int rev):to(to),cap(cap),rev(rev) {}
};

int e=-1;
int choose;
int n;
LinkNode *HeadNode ,*p;
TreeNode *root;


vector<string> Inf;
stack<int> Stack;
vector<NetEdge>g[100];///图的邻接表

map<int ,string>Name;

int parent[0x3f3f3f];
int Map[100][100];
int Minimal_Tree[100][100];
int LostMap[1000][1000];

int Flow[1000][1000];
int level[100];///顶点到源点的距离标号
int iter[100];///当前弧,在其之前的边已经没用了

void HeadNode_Creat(LinkNode  *&HeadNode)
{
    HeadNode=new LinkNode;
    HeadNode->next=NULL;
}

void addedge(int from,int to,int cap)
{
    
    g[from].push_back(NetEdge(to,cap,(int)g[to].size()));
    g[to].push_back(NetEdge(from,0,(int)g[from].size()-1));
}
void Creat_Name(LinkNode *HeadNode )
{
    LinkNode *p;
    int i=0;
    p=HeadNode->next;
    while(p){
        Name.insert(pair<int ,string>(i++,p->Name));
        p=p->next;
    }
}

void LinkNode_Insert_Tail(LinkNode *&HeadNode,string name){
    LinkNode *node ,*p;
    node =new LinkNode;
    node ->Name=name;
    p=HeadNode;
    while(p->next) p=p->next;
    p->next=node;
    node ->next=NULL;
}

void Read(){
    ifstream in("File.txt");
    string name ;
    getline(in,name);
    istringstream iss(name); iss>>n;
    HeadNode_Creat(HeadNode);
    for(int i=0;i<n;i++){
        getline(in,name);
        LinkNode_Insert_Tail(HeadNode ,name);
    }
    string information;
    for(int i=0;i<=n;i++){               //考虑到地图数量可能会很多,景点信息开数组无法保存,所以采用C++ 中 vector对节点信息进行保存,vector是在堆上进行操作
        getline(in, information);
        if(name.length()!=0)
        Inf.push_back(information);
    }
    
    for(int i=0;i<n;i++)               //地图读入
        for(int j=0;j<n;j++)
            in>>Map[i][j];
    
    
    for(int i=0;i<10000;i++)   parent[i]=i;       //并查集数组parent[] 初始化
    
    
    
    for(int i=0;i<n;i++)                  //流量数组
        for(int j=0;j<n;j++){
            in>>Flow[i][j];
        }
    
    bool NetVis[1000][1000];            //因为网络流是无向的,所以我们对一些重复的边进行去重
    memset(NetVis, false, sizeof NetVis);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(Flow[i][j]>0&&!NetVis[i][j]&&!NetVis[j][i]){   //网络流图为无向,标记是否访问过,根据访问情况进行边的添加;
                addedge(i, j, Flow[i][j]);
                NetVis[i][j]=NetVis[j][i]=true;           //标记,如果已经输入则不再赋值
            }
        }
    }
}

void ShowOut_Link(LinkNode *&HeadNode){       // 输出景点名称链表 (递归方式)
    p=HeadNode->next;
    while(p){
        cout<<p->Name<<" "<<endl;
        p=p->next;
    }
}

TreeNode *TreeNode_Creat()                         // 创建字典树,实现快速查询
{
    TreeNode * k=new(TreeNode);
    k->count=0;
    memset(k->next,NULL,sizeof(k->next));
    k->num=-1;                                    //Inf信息数组下标
    return k;
}

void TreeNode_Insert(string name,TreeNode *&root,int num)   //景点的插入,将num 号挂在叶子结点的下面
{
    int i=0;
    TreeNode * r=root;
    while(i<=name.length())
    {
        int id=name[i]-'a';
        if(r->next[id]==NULL)
            r->next[id]=TreeNode_Creat();
        r=r->next[id];
        if(i==name.length()-1)
        {
            r->count++;                //最后一个字母计数,表示有以当前字母为结尾的景点
            r->num=num;
        }
        i++;
    }
}

void Creat_Tree(TreeNode *& root,LinkNode *& HeadNode ){ //根据景点名称的链表创建字典树
    p=HeadNode->next;
    int num=0;
    while(p) {
    
        TreeNode_Insert(p->Name,root,num++);
        p=p->next;
    }
}

bool TreeNode_Search(TreeNode *& root,string name,int &e){   //查找景区标识号,如果查到则返回true, 由 e 带会标识号,否则返回false ;
    TreeNode *r;
    r=root;
    for(int i=0;i<name.length();i++){
        if(r->next[name[i]-'a']!=0)
            r=r->next[name[i]-'a'];
        else return false;
    }
    e=r->num;
    return true;
}

Edge *Creat_Edge_HeadNode(){
    Edge * p;
    p=new Edge;
    p->next=NULL;
    return p;
}

void Edge_Insert(Edge *&Edge_HeadNode,int u,int v ,int w){  //创建图的边链表(尾插法)
    Edge *p,*node;
    node=new Edge;
    node->u=u;
    node->v=v;
    node->w=w;
    node->next=NULL;
    p=Edge_HeadNode;
    while(p->next) p=p->next;
    p->next=node;
}

Edge *Creat_Edge_LinkNode(){
    Edge *Edge_HeadNode;
    Edge_HeadNode=Creat_Edge_HeadNode();               //建立头节点
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(Map[i][j]){
                Edge_Insert(Edge_HeadNode,i,j,Map[i][j]);
            }
    return Edge_HeadNode;
}

int find(int x){
    return parent[x] == x ? x : find(parent[x]);
}

void ShowOut_Minimal_Spanning_Tree(){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)
            cout<<setw(8)<<Minimal_Tree[i][j];
        cout<<endl;
    }
}


void Kruskal(Edge *Edge_HeadNode){
    memset (Minimal_Tree , -1 ,sizeof Minimal_Tree);
    priority_queue<edge, vector<edge>, cmp> minHeap;               //c++ 定义STL 最小堆
    Edge *p;
    edge q;
    p=Edge_HeadNode->next;
    while(p){
        q.u=p->u;
        q.v=p->v;
        q.w=p->w;
        minHeap.push(q);
        p=p->next;
    }
    int k=0;
    while(!minHeap.empty()){
        q=minHeap.top();
        minHeap.pop();
        int x1=find(q.u);
        int x2=find(q.v);
        if(x1!=x2) {
            parent[x1]=parent[x2];
            k++;
            Minimal_Tree[q.u][q.v]=q.w ;
        }
        if(k==n-1){
            ShowOut_Minimal_Spanning_Tree();
            return;
        }
    }
}

void ShowOut_way(int *pre,int x,int start){     //输出所有的路径
    cout<<Name[x]<<"->";
    while(pre[x]!=-1)
    {
        cout<<Name[pre[x]];
        x=pre[x];
        if(x!=start) cout<<"->";
    }
}

void SPFA(int s,int *dis,int *pre){
    queue<int> Q;
    while(!Q.empty()) Q.pop();
    bool vis[100000];
    memset (vis , false ,sizeof vis);
    for(int i=0; i<n; i++) dis[i]=0x3f3f;
    dis[s]=0; vis[s]=true;
    Q.push(s);
    while(!Q.empty()){
        int t=Q.front();
        Q.pop();
        vis[t]=false;
        for(int i=0;i<n;i++){
            if(Map[t][i]>0&&dis[i]>dis[t]+Map[t][i]){
                dis[i]=dis[t]+Map[t][i];
                pre[i]=t;
                if(vis[i]==false){
                    Q.push(i);
                    vis[i]=true;
                }
            }
        }
    }
}


void ShowOut_Map()
{
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)
            cout<<setw(5)<<Map[i][j];
        cout<<endl;
    }
}


int Shortest_Path(int from,int to){
    int pre[100000];
    int dis[100000];
    memset(pre , -1 ,sizeof pre);
    SPFA(from, dis,pre);
    cout<<"输出路径"<<endl;
    ShowOut_way(pre, to,from);
    return dis[to];
    
}

void Topological_Sort_FindCircle(){
    int In[2000];
    int Out[2000];
    int TopoInt[1000][1000];
    memset (TopoInt, 0 ,sizeof TopoInt);
    for(int i=0;i<n;i++)           //构建临时地图数组
        for(int j=0;j<n;j++)
            if(Map[i][j]>0)
                TopoInt[i][j]=Map[i][j];
    
    memset (In , 0 ,sizeof In);
    memset (Out , 0 ,sizeof Out);
    
    vector<int>ans;
    queue<int >Topo;
    
    for(int i=0;i<n;i++)          //找出节点的出度和入度
        for(int j=0;j<n;j++)
            if(i!=j)
                if(Map[i][j]>0){
                    In[j]++;
                    Out[i]++;
                }
    
    for(int i=0;i<n;i++)
        if(!In[i])    Topo.push(i);
    while(!Topo.empty()){
        int p=Topo.front();
        Topo.pop();
        ans.push_back(p);
        for(int i=0;i<n;i++)
            if(Map[p][i]>0){
                In[i]--;
                TopoInt[p][i]=0;           //删除多余的度
                if(!In[i]) Topo.push(i);   //入度为0的加入队列
            }
    }
    if(ans.size()==n)
        cout<<"该地图没有环"<<endl;
    else {
        
        
        
        
        for(int i=0;i<n;i++){              //输出辅助数组以此来表示环
            for(int j=0;j<n;j++)
                cout<<setw(8)<<TopoInt[i][j];
            cout<<endl;
        }
    }
}

void Show_Out_Way(){             //递归输出路径
    if(!Stack.empty()){
        int p=Stack.top();
        Stack.pop();
        Show_Out_Way();
        //cout<<setw(8)<<p;
        cout<<Name[p]<<"->";
        Stack.push(p);
  
    }
}

void Deep_First_Search(int from ,int end,bool *vis){
    if(from==end) {
        cout<<"找到路径"<<endl;
       // cout<<" Stack.top()"<<Stack.top()<<endl;
        Show_Out_Way();
        cout<<endl;
        return ;
        
    } //确保输出的路径是有终点的
    
    for(int i=0;i<n;i++)
    {
        if(!vis[i]&&Map[from][i]>0){ //未访问并且有路
            vis[i]=true;
          //  cout<<"i="<<i<<"进栈"<<endl;
            Stack.push(i);
            Deep_First_Search(i, end, vis);
           // cout<<"i="<<i<<"出栈"<<endl;
            Stack.pop();
            vis[i]=false;
        }
    }
}

void Find_All_Way(int from ,int end){
    bool vis[10000];
    while(!Stack.empty()) Stack.pop();
    memset(vis, false, sizeof vis);
    Stack.push(from);
    vis[from]=true;
    Deep_First_Search(from, end, vis);
}

int Find(int s,int v ,int end,int dp[1<<15][100],int pre[1000]){      //查找路线可以经过每一个景点并且不会重复
   // cout<<s<<endl;
    if(dp[s][v]>0)
        return dp[s][v];
    if(s==(1<<n)-1&&v==end){
        return 0;
    }
    int res=0x3f3f3f;
    for(int u=0;u<n;u++){
        if(!((s>>(u))&1)&&Map[v][u]>0){
            //            cout<<"u="<<u<<"未a访问"<<endl;
            //            bitset<6> t(s);
            //            cout<<"s= "<<t<<endl;
            //            cout<<"传入"<<(s|(1<<u))<<endl;
            if(res>Find(s|(1<<(u)),u ,end,dp,pre)+Map[v][u]){
                pre[v]=u;
                res=Find(s|(1<<(u)),u ,end,dp,pre)+Map[v][u];
            }
        }
    }
    return res;
}

void Show_Hamilton(int *pre,int x){      //pre[ ]记录结点的前一个结点 ,递归输出哈密顿d图
    
    if(pre[x]!=-1){
        cout<<Name[pre[x]]<<" ->";
        Show_Hamilton(pre, pre[x]);
    }
    
}

void Show(int *pre,int x){
    cout<<Name[x]<<"-> ";
    Show_Hamilton(pre, x);
}

void Only_Way(int start,int end){
    //cout<<"345"<<endl;
    int dp[1<<10][100];           //状压dp
    int pre[100];               //记录路径

    memset(pre,-1,sizeof pre);
    memset(dp, -1, sizeof dp);
    //cout<<"11111"<<endl;
    cout<<"哈密顿图的长度为"<<Find(1<<start,start,end,dp,pre)<<endl;
    cout<<endl;
    Show(pre,start);
}

///通过bfs计算从源点出发的距离标号
void BFS(int s)           //对图进行分层
{
    
    memset(level , -1 , sizeof level);
    queue<int>que;
    level[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=0;i<g[v].size();i++)
        {
            NetEdge &e=g[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}

///通过dfs寻找增广路

int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v]; i<g[v].size(); i++)
    {
        NetEdge &e=g[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                g[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}


int Max_NetWork_Flow(int s,int t)
{
    int flow=0;
    while(1)
    {
        BFS(s);
        if(level[t]<0)
            return flow;
        memset(iter , 0 , sizeof iter);
        int f;
        while((f=dfs(s,t,0x3f3f3f))>0)
            flow+=f;
    }
}

void Inite(){
    HeadNode_Creat(HeadNode);
    Read();
    root=TreeNode_Creat();
    Creat_Tree(root, HeadNode);
    Creat_Name(HeadNode);
}


int main()
{
    Inite();
    cout<<"**************************************************"<<endl;
    cout<<"*          欢迎使用景区旅游信息管理系统          *"<<endl;
    cout<<"*                  请选择菜单                    *"<<endl;
    cout<<"**************************************************"<<endl;
    cout<<"*            1.输出景点列表                *"<<endl;
    cout<<"*            2.查找两景区间的所有路径               *"<<endl;
    cout<<"*            3.输出导游线路图                    *"<<endl;
    cout<<"*            4.判断导游线路图有无回路并输出      *"<<endl;
    cout<<"*            5.求两个景点间的最短路径和最短距离  *"<<endl;
    cout<<"*            6.输出道路修建规划图                *"<<endl;
    cout<<"*            7.判断两地之间的最大流              *"<<endl;
    cout<<"*            8.查询景点的详细信息                *"<<endl;
    cout<<"*            9.输出不重复走过所有景点的路径      *"<<endl;
    cout<<"*            0.退出系统                          *"<<endl;
    cout<<"**************************************************"<<endl;
    cout<<"请输入您要选择的菜单项..."<<endl;
    while(1){
        cin>>choose;
        while(choose<0&&choose>9) cin>>choose;
        switch(choose)
        {
            case 1:
                ShowOut_Link(HeadNode);
                break;
            case 2:
            {
                string name1,name2;
                cout<<"输入第一个景点"<<endl;
                cin>>name1;
                cout<<"输入第二个景点"<<endl;
                cin>>name2;
                cout<<endl;
                int num1=-1,num2=-1;
                if(TreeNode_Search(root, name1, num1)&&TreeNode_Search(root, name2, num2))
                    Find_All_Way(num1, num2);
                else cout<<"输入景点有误"<<endl;
                break;
            }
            case 3:
                ShowOut_Map();
                break;
            case 4:
                Topological_Sort_FindCircle();
                break;
            case 5:
            {
                int num1=-1,num2=-1;
                string name1,name2;
                cout<<"输入第一个景点"<<endl;
                cin>>name1;
                cout<<"输入第二个景点"<<endl;
                cin>>name2;
                cout<<endl;
          
                if(TreeNode_Search(root, name1, num1)&&TreeNode_Search(root, name2, num2)){
                    int res = Shortest_Path(num1, num2);
                    cout<<"最短距离="<<res<<endl;
                }
                else cout<<"输入景点有误"<<endl;
                break;
            }
            case 6:
                Kruskal( Creat_Edge_LinkNode());
                break;
            case 7:
            {
                string name1,name2;
                cout<<"输入你要查询的两地间最大客流量的景点"<<endl;
                cout<<"输入第一个景点"<<endl;
                cin>>name1;
                cout<<"输入第二个景点"<<endl;
                cin>>name2;
                cout<<endl;
                int num1=-1,num2=-1;
                if(TreeNode_Search(root, name1, num1)&&TreeNode_Search(root, name2, num2))
                    cout<<Max_NetWork_Flow(num1, num2);
                else cout<<"输入景点有误"<<endl;
                break;
            }
            case 8:
            {
                string name ;
                cout<<"输入你要查询的景区的名称"<<endl;
                cin>>name;
                if(TreeNode_Search(root, name, e))
                    cout<<Inf[e]<<endl;
                else cout<<"输入的景点不存在"<<endl;
                cout<<"e="<<e<<endl;
                break;
            }
            case 9:
            {
                string name1,name2;
//                cout<<"输入你要查询的两地间最大客流量的景点"<<endl;
                cout<<"输入第一个景点"<<endl;
                cin>>name1;
                cout<<"输入第二个景点"<<endl;
                cin>>name2;
                cout<<endl;
                int num1=-1,num2=-1;
                if(TreeNode_Search(root, name1, num1)&&TreeNode_Search(root, name2, num2))
                    Only_Way(num1, num2);
                else cout<<"输入景点有误"<<endl;
                break;
            }
            case 10:{
                cout<<"测试功能"<<endl;
                
                
            }
            case 0:
                exit(1);
        }
        
    }
    
}

文件

5
aa
bb
cc
dd
ee
111111
22222
3333
444
5555

0 1 1 0 0
0 0 0 1 1
1 0 0 1 1
0 1 1 0 0
0 1 1 0 0

0 1 1 0 0
1 0 0 1 1
1 0 0 1 1
0 1 1 0 0
0 1 1 0 0
 

猜你喜欢

转载自blog.csdn.net/qq_41421433/article/details/89087659
今日推荐