//
// 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