目录
题目一(哈利.波特的考试):
代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int v,w;
bool operator <(const node&y) const
{return w>y.w;}
};
vector<node> e[110];
int dis[110],vis[110];
void dij(int t)
{
priority_queue<node> q;
dis[t]=0;
q.push({t,dis[t]});
while(q.size())
{
int u=q.top().v;
q.pop();
if(vis[u])
continue;
vis[u]=1;
for(auto i:e[u])
{
int v=i.v,w=i.w;
if(vis[v]==0)
{
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push({v,dis[v]});
}
}
}
}
}
int main()
{
int n,m;
cin>>n>>m;
while(m--)
{
int v1,v2,w;
cin>>v1>>v2>>w;
e[v1].push_back({v2,w});
e[v2].push_back({v1,w});
}
int flag,minn=1e9;//flag标记编号,minn存魔咒最短的值
int s=0;//记录无法连通的个数
for(int i=1;i<=n;i++)//从每个点开始做dij
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dij(i);//迪杰斯特拉
int maxx=0;//记录该点出发到其它点的最长距离
for(int i=1;i<=n;i++)
{
if(dis[i]>maxx)
{
maxx=dis[i];
}
}
int cnt=0;//标记是否有没访问到的
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
cnt=1;
break;
}
}
if(maxx<minn && cnt==0)//最长的魔咒比之前的短且没有不访问的点,则更新
{
flag=i,minn=maxx;
}
if(cnt==1)//有没访问的,s加一
s++;
}
if(s==n)//无法只带一只动物
cout<<0;
else
cout<<flag<<" "<<minn;
}
题目二(旅游规划):
代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int v, w, z;
bool operator <(const node& y)const
{
return w < y.w;
}
};
priority_queue<node> q;
vector<node> e[10100];
int dis[1000], vis[1000], val[1000];
void dij(int t)
{
memset(dis, 0x3f3f3f, sizeof(dis));
dis[t] = 0;
val[t] = 0;
q.push({ t,dis[t] });
while (q.size())
{
int u = q.top().v;
q.pop();
if (vis[u])
continue;
for (auto i : e[u])
{
int v = i.v, w = i.w, z = i.z;
if (vis[v] == 0)
{
if (dis[v] > dis[u] + w)//距离更短,更新
{
dis[v] = dis[u] + w;//更新距离
val[v] = val[u] + z;//更新花费
q.push({v,dis[v]});
}
if (dis[v] == dis[u] + w && val[v] > val[u] + z)//距离相等,花费更小,更新
{
val[v] = val[u] + z;
}
}
}
}
}
int main()
{
int n, m, s, d;
cin >> n >> m >> s >> d;
while (m--)
{
int x1, x2, v, w;
cin >> x1 >> x2 >> v >> w;
e[x1].push_back({ x2,v,w });//无向图,建图
e[x2].push_back({ x1,v,w });
}
dij(s);
cout << dis[d] << " " << val[d] << endl;
}
题目三(城市间的紧急救援):
代码:
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
struct node
{
int v, w;
bool operator <(const node& y) const
{
return w > y.w;
}
};
priority_queue<node> q;
vector<node> e[101000];
int dis[1010], vis[1010], path[1010], jiu[1010], path_count[1010], val[1010];
void dij(int t)
{
memset(dis, 0x3f3f3f, sizeof(dis));
jiu[t] = val[t];//初始救援人数等于起点救援人数
dis[t] = 0;
path[t] = t;//初始前驱为自身
path_count[t] = 1;//初始路径数量为1
q.push({ t,dis[t] });
while (q.size())
{
int u = q.top().v;
q.pop();
if (vis[u])//访问过
continue;
vis[u] = 1;
for (auto i : e[u])
{
int v = i.v, w = i.w;
if (vis[v] == 0)//没访问过
{
if (dis[v] > dis[u] + w)//距离更短
{
jiu[v] = jiu[u] + val[v];//救援数等于前驱的加上自身的
dis[v] = dis[u] + w;
path[v] = u;//记录前驱
path_count[v] = path_count[u];//路径数为前驱路径数
q.push({ v,dis[v] });
}
else if (dis[v]==dis[u]+w)//距离相等
{
path_count[v] += path_count[u];//路径数自身加上前驱的
if (jiu[v] < val[v] + jiu[u])//救援人员更多,则更新
{
jiu[v] = val[v] + jiu[u];
path[v] = u;
}
}
}
}
}
}
int main()
{
int n, m, s, d;
cin >> n >> m >> s >> d;
for (int i = 0; i < n; i++)//救援队数
cin >> val[i];
for (int j = 0; j < m; j++)//无向图,建边
{
int v1, v2, w;
cin >> v1 >> v2 >> w;
e[v1].push_back({ v2,w });
e[v2].push_back({ v1,w });
}
dij(s);
cout << path_count[d] << " ";
cout << jiu[d] << endl;
int a[1010];
int k = 0;
while (d != s)//存路径
{
a[k] = d;
d = path[d];
k++;
}
cout << s << " ";
for (int i = k - 1; i >= 0; i--)//反向输出路径
{
if (i != k - 1)
cout << " ";
cout << a[i];
}
}
题目四(天梯地图):
代码:
#include<iostream>//最后一个测试点没过
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int v, w,z;
bool operator <(const node& y) const
{
return w > y.w;
}
};
vector<node> e[1010];
int dist[1010], disd[1010], vis[1010];
string pathd[1010] = { "" }, patht[1010] = { "" };//分别记录最短距离,最短时间
void dijd(int t, int dis[], string path[])//求最短路径
{
memset(vis, 0, sizeof(vis));
priority_queue<node> q;
int cnt[1010]={0};//记录访问城市个数
memset(cnt, 0, sizeof(cnt));
cnt[t]=1;//初始访问一个
dis[t] = 0;
char c = t + '0';//int类型转为char
path[t] += c;//自身前驱记录为自身
q.push({ t,dis[t] });
while (q.size())
{
int u = q.top().v;
q.pop();
if (vis[u])//访问过
continue;
vis[u] = 1;
for (auto i : e[u])
{
int v = i.v, w = i.w;
if (vis[v] == 0)//没访问过
{
char c = v + '0';//int传为char
if (dis[v] > dis[u] + w)//距离更短,更新
{
dis[v] = dis[u] + w;//更新距离
path[v]="";
path[v] = path[u] + c;//路径为前驱加上自身
cnt[v]=cnt[u]+1;//访问城市数量等于前驱数量加自身
q.push({ v,dis[v] });//入队
}
else if (dis[v] == dis[u] + w && cnt[v] > cnt[u] + 1)//距离一样,访问城市更少,更新
{
cnt[v]=cnt[u]+1;//访问城市数量等于前驱数量加自身
path[v]="";
path[v] = path[u] + c;//路径为前驱加上自身
}
}
}
}
}
void dijt(int t, int dis[], string path[])//求最短时间
{
memset(vis, 0, sizeof(vis));
priority_queue<node> q;
int cnt[1010];//记录到该点的距离
memset(cnt, 0, sizeof(cnt));
cnt[t] = 0;//初始点距离为0
dis[t] = 0;
char c = t + '0';
path[t] += c;//初始前驱为自身
q.push({ t,dis[t] });
while (q.size())
{
int u = q.top().v;
q.pop();
if (vis[u])//访问过
continue;
vis[u] = 1;
for (auto i : e[u])
{
int v = i.v, z = i.z, w=i.w;
if (vis[v] == 0)
{
char c = v + '0';//int转char
if (dis[v] > dis[u] + z)//时间更短,更新
{
dis[v] = dis[u] + z;//更新时间
cnt[v] = cnt[u] + w;//更新距离
path[v]="";
path[v] = path[u] + c;//路径为前驱加上自身
q.push({ v,dis[v] });
}
else if (dis[v] == dis[u] + z && cnt[u]+w<cnt[v])//时间相等,距离更短,更新
{
cnt[v] = cnt[u]+w;//更新距离
path[v]="";
path[v] = path[u] + c;//路径为前驱加上自身
}
}
}
}
}
int main()
{
int n, m;
cin >> n >> m;
while (m--)
{
int v1, v2, o, l, t;
cin >> v1 >> v2 >> o >> l >> t;
if (o == 1)
{
e[v1].push_back({ v2,l,t });
}
else
{
e[v1].push_back({ v2,l,t });
e[v2].push_back({ v1,l ,t});
}
}
int s, d;
cin >> s >> d;
memset(dist, 0x3f3f3f3f, sizeof(dist));
memset(disd, 0x3f3f3f3f, sizeof(disd));
dijt(s, dist, patht);
dijd(s, disd, pathd);
if (pathd[d] != patht[d])//路径 不相同 分别输出
{
cout << "Time = " << dist[d] << ": ";
for (int j = 0; j < patht[d].size(); j++)
{
if (j != 0)
cout << " => ";
cout << patht[d][j];
}
cout << endl;
cout << "Distance = " << disd[d] << ": ";
for (int j = 0; j < pathd[d].size(); j++)
{
if (j != 0)
cout << " => ";
cout << pathd[d][j];
}
}
else//路径相同
{
cout << "Time = " << dist[d] << "; " << "Distance = " << disd[d] << ": ";
for (int j = 0; j < pathd[d].size(); j++)
{
if (j != 0)
cout << " => ";
cout << pathd[d][j];
}
}
}
题目五(直捣黄龙):
代码:
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
int v;
int w;
bool operator <(const node& y)const
{
return w > y.w;
}
};
map<string, int> v;//通过城市名访问敌军数
map<int, string> names;//通过编号访问城市名
map<string, int>id;//通过城市名访问编号
vector<node> e[1010];//存边
int dis[1010], vis[1010], path[1010], shu[1010], dr[1010];//vis访问数组,path存路径,shu存路径数量,dr存敌人数量
priority_queue<node> q;
void dij(int t)
{
memset(dis, 0x3f3f3f3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
int cnt[1010];//经过城市的个数
memset(cnt, 0, sizeof(vis));
shu[t] = 1;//初始路径为1
cnt[t] = 1;//初始经过城市1
dr[t] = 0;//初始敌人为0
path[t] = t;//初始前驱为自身
dis[t] = 0;
q.push({ t,dis[t] });
while (q.size())
{
int u = q.top().v;//取边最小的点
q.pop();
if (vis[u])//访问过,跳过
continue;
vis[u]=1;
for (auto i : e[u])//访问相连边
{
int v1 = i.v, w = i.w;//取相连点和权值
if (vis[v1] == 0)
{
if (dis[v1] > dis[u] + w)//长度更短,更新
{
shu[v1] = shu[u];//到该点的路径数继承前驱的路径数
path[v1] = u;//保存前驱
dis[v1] = dis[u] + w;//更新最短长度
cnt[v1]=cnt[u]+1;//经过的城市为前驱+自身
dr[v1] = dr[u] + v[names[v1]];//敌人数量为前驱加自身城市的敌人数量
q.push({ v1,dis[v1] });//入队
}
else if (dis[v1] == dis[u] + w)//长度相同
{
shu[v1] += shu[u];//路径数自身原本的加上该前驱的路径数
if (cnt[v1] < cnt[u] + 1)//访问城市比之前多,更新
{
cnt[v1] = cnt[u] + 1;//更新访问数量
path[v1] = u;//更新前驱
dr[v1] = dr[u] + v[names[v1]];//更新敌人数量
}
else if (cnt[v1] == cnt[u] + 1 && dr[v1] < dr[u] + v[names[v1]])//路径相同,访问城市数量相同,敌人更大,更新
{
path[v1] = u;//更新前驱
dr[v1] = dr[u] + v[names[v1]];//更新敌人数
}
}
}
}
}
}
int main()
{
int n, k;
string s, d;
cin >> n >> k >> s >> d;
v[s] = 0;//大本营,敌人数量为0
names[1] = s;//大本营编号为1
id[s] = 1;//大本营编号为1
for (int i = 2; i <= n; i++)
{
string name;
int num;
cin >> name >> num;
v[name] = num;//通过名字访问敌军数量
names[i] = name;//通过编号访问名字
id[name] = i;//通过名字访问编号
}
while (k--)
{
string s1, s2;
int w;
cin >> s1 >> s2 >> w;
int a = id[s1];
int b = id[s2];
e[a].push_back({ b,w });//建立边,无向图
e[b].push_back({ a,w });
}
dij(id[s]);
//for (int i = 1; i <= n; i++)
//cout << dis[i] << " ";
int t = id[d];
string a[1010];
k = 0;
while (path[t] != t)//保存节点
{
a[k++] = names[t];
//cout<<names[t]<<" ";
t = path[t];
}
a[k] = s;
for (int i = k; i >= 0; i--)//倒序输出
{
if (i != k)
cout << "->";
cout << a[i];
}
cout << endl;
cout << shu[id[d]] << " " << dis[id[d]] << " " << dr[id[d]];
}