1031. Campus
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
At present, Zhongshan University has 4 campuses with a total area of 6.17 square kilometers sitting respectively on both sides of the Pearl River or facing the South China Sea. The Guangzhou South Campus covers an area of 1.17 square kilometers, the North Campus covers an area of 0.39 square kilometers, the Guangzhou East Campus has an area of 1.13 square kilometers and the Zhuhai Campus covers an area of 3.48 square kilometers. All campuses have exuberance of green trees, abundance of lawns and beautiful sceneries, and are ideal for molding the temperaments, studying and doing research.

Sometime,
the professors and students have to go from on
Input
The first line of the input is a positive integer C. C is the number of test cases followed. In each test case, the first line is a positive integer N (0<N<=100) that represents the number of roads. After that, N lines follow. The i-th(1<=i<=N) line contains
two strings Si, Ti and on
Output
The output of the program should consist of C lines, on
Sample Input
1 2 South.xiaolitang South.xiongdelong 2 South.xiongdelong Zhuhai.liyuan 100 South.xiongdelong South.xiaolitang
Sample Output
2
Problem Source
ZSUACM Team Member
极度坑爹的一题,不过也学到了很多,顺便以这道来研究最短路径问题好了,注意地点相同的特殊情况(坑),还有一个要记住的地方就是丫的给你100条路最多可以有200个地方啊- -
首先是没有用map的Floyd-Warshall算法:
#include <stdio.h>
#include <string.h>
#define INF 99999999
#define MAX 115 * 2
int total_num_of_name, map[MAX][MAX];
char num_of_name[MAX][MAX];
int min(int a, int b) {
return a > b ? b : a;
}
void make_map(char f[], char t[], int dis) {
int i, t_num, f_num;
for (i = 0; i < total_num_of_name; i++) {
if (strcmp(f, num_of_name[i]) == 0) {
f_num = i;
break;
}
}
if (i >= total_num_of_name) {
f_num = total_num_of_name;
strcpy(num_of_name[total_num_of_name++], f);
}
for (i = 0; i < total_num_of_name; i++) {
if (strcmp(t, num_of_name[i]) == 0) {
t_num = i;
break;
}
}
if (i >= total_num_of_name) {
t_num = total_num_of_name;
strcpy(num_of_name[total_num_of_name++], t);
}
map[f_num][t_num] = dis < map[f_num][t_num] ? dis : map[f_num][t_num];
map[t_num][f_num] = dis < map[t_num][f_num] ? dis : map[t_num][f_num];
}
int find_num(char a[]) {
for (int i = 0; i < total_num_of_name; i++) {
if (strcmp(a, num_of_name[i]) == 0)
return i;
}
return -1;
}
void Floyd_Warshall() {
int i, j, k;
for (i = 0; i < MAX; i++) {
map[i][i] = 0;
}
for (k = 0; k < total_num_of_name; k++) {
for (i = 0; i < total_num_of_name; i++) {
for (j = 0; j < total_num_of_name; j++) {
map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
}
}
}
}
int main() {
int case_num, n, dis, f_num, t_num;
char temp_f[MAX], temp_t[MAX];
scanf("%d", &case_num);
while (case_num--) {
scanf("%d", &n);
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
map[i][j] = INF;
}
}
memset(num_of_name, '\0', sizeof(num_of_name));
total_num_of_name = 0;
while (n--) {
memset(temp_f, '\0', sizeof(temp_f));
memset(temp_t, '\0', sizeof(temp_t));
scanf("%s %s %d", temp_f, temp_t, &dis);
make_map(temp_f, temp_t, dis);
}
scanf("%s%s", &temp_f, &temp_t);
if (strcmp(temp_f, temp_t) == 0) {
printf("0\n");
continue;
}
f_num = find_num(temp_f);
t_num = find_num(temp_t);
if (f_num == -1 || t_num == -1) {
printf("-1\n");
continue;
}
Floyd_Warshall();
printf("%d\n", map[f_num][t_num] >= INF ? -1 : map[f_num][t_num]);
}
return 0;
}
然后试试用map:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
#include <string>
using namespace std;
#define INF 99999999
#define MAX 115 * 2
int total_num_of_name, mapp[MAX][MAX];
char num_of_name[MAX][MAX];
int min(int a, int b) {
return a > b ? b : a;
}
void Floyd_Warshall() {
int i, j, k;
for (i = 0; i < MAX; i++) {
mapp[i][i] = 0;
}
for (k = 0; k < total_num_of_name; k++) {
for (i = 0; i < total_num_of_name; i++) {
for (j = 0; j < total_num_of_name; j++) {
mapp[i][j] = min(mapp[i][j], mapp[i][k] + mapp[k][j]);
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
int case_num, n, dis;
string temp_f, temp_t;
cin >> case_num;
while (case_num--) {
cin >> n;
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
mapp[i][j] = INF;
}
}
total_num_of_name = 0;
map<string, int> m;
while (n--) {
cin >> temp_f >> temp_t >> dis;
if (m.find(temp_f) == m.end()) {
m[temp_f] = total_num_of_name++;
}
if (m.find(temp_t) == m.end()) {
m[temp_t] = total_num_of_name++;
}
mapp[m[temp_f]][m[temp_t]] = dis < mapp[m[temp_f]][m[temp_t]] ? dis : mapp[m[temp_f]][m[temp_t]];
mapp[m[temp_t]][m[temp_f]] = dis < mapp[m[temp_t]][m[temp_f]] ? dis : mapp[m[temp_t]][m[temp_f]];
}
cin >> temp_f >> temp_t;
if (temp_f == temp_t) {
cout << 0 << endl;
continue;
}
if (m.find(temp_f) == m.end() || m.find(temp_t) == m.end()) {
cout << -1 << endl;
continue;
}
Floyd_Warshall();
cout << (mapp[m[temp_f]][m[temp_t]] >= INF ? -1 : mapp[m[temp_f]][m[temp_t]]) << endl;
}
return 0;
}
有map的Dijkstra:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
#include <string>
using namespace std;
#define INF 99999999
#define MAX 115 * 2
int total_num_of_name, mapp[MAX][MAX];
char num_of_name[MAX][MAX];
int min(int a, int b) {
return a > b ? b : a;
}
///////////////////////////////////////Dijkstra///////////////////////////////////////
int Dijkstra(int start_point, int end_point) {
int dis_from_sp[MAX]; //各个点到起点的最短距离
fill(dis_from_sp, dis_from_sp + total_num_of_name, INF); //一开始为INF
bool used_point[MAX]; //各个点是否用过来扩展更新最短路径,这里的点是dis_from_sp中的点
fill(used_point, used_point + total_num_of_name, false);
dis_from_sp[start_point] = 0; //起点特殊
while (1) {
int v = -1;
for (int i = 0; i < total_num_of_name; i++) { //从dis_from_sp中找出一个没有用过的而且到起点距离最小的点来更新起点到各个点的最短路径
if (!used_point[i] && (v == -1 || dis_from_sp[i] < dis_from_sp[v]))
v = i;
}
if (v == -1) //如果还是-1说明dis_from_sp中的点都已经用完了
break;
used_point[v] = true;
for (int i = 0; i < total_num_of_name; i++) { //通过中间点(当前到起点的最短点)来更新最短路径
dis_from_sp[i] = min(dis_from_sp[i], dis_from_sp[v] + mapp[v][i]);
}
}
return dis_from_sp[end_point]; //最后只需要返回终点到起点的最短路径就可以了
}
///////////////////////////////////////Dijkstra///////////////////////////////////////
int main() {
std::ios::sync_with_stdio(false);
int case_num, n, dis;
string temp_f, temp_t;
cin >> case_num;
while (case_num--) {
cin >> n;
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
mapp[i][j] = INF;
}
}
total_num_of_name = 0;
map<string, int> m;
while (n--) {
cin >> temp_f >> temp_t >> dis;
if (m.find(temp_f) == m.end()) {
m[temp_f] = total_num_of_name++;
}
if (m.find(temp_t) == m.end()) {
m[temp_t] = total_num_of_name++;
}
mapp[m[temp_f]][m[temp_t]] = dis < mapp[m[temp_f]][m[temp_t]] ? dis : mapp[m[temp_f]][m[temp_t]];
mapp[m[temp_t]][m[temp_f]] = dis < mapp[m[temp_t]][m[temp_f]] ? dis : mapp[m[temp_t]][m[temp_f]];
}
cin >> temp_f >> temp_t;
if (temp_f == temp_t) {
cout << 0 << endl;
continue;
}
if (m.find(temp_f) == m.end() || m.find(temp_t) == m.end()) {
cout << -1 << endl;
continue;
}
for (int i = 0; i < total_num_of_name; i++) {
mapp[i][i] = 0;
}
int ans = Dijkstra(m[temp_f], m[temp_t]);
cout << (ans < INF ? ans : -1) << endl;
}
return 0;
}
优化的Dijkstra算法:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 99999999
#define MAX 115 * 2
//这次也是Dijkstra算法,但是在数值的插入和取最小值方面进行了优化,使用了优先队列,这样经过自动排序后,每次可以直接从队首取得距离起点最小值
int total_num_of_name;//点的总数
struct edges {//用结构体作为二维动态数组的元素存图
int to;//到达的点
int diss;//距离
edges(int new_to, int new_diss): to(new_to), diss(new_diss){}//结构体的初始化函数
};
vector<edges> e[MAX];//用结构体作为二维动态数组的元素存图
typedef pair<int, int> p;//优先队列里的元素,first是到起点距离,second是点号
int Dijkstra(int start_point, int end_point) {
int dis_from_sp[MAX];//到起点的距离
fill(dis_from_sp, dis_from_sp + total_num_of_name, INF);//初始化
dis_from_sp[start_point] = 0;//起点的特殊处理
priority_queue<p, vector<p>, greater<p> > q;//优先队列,greater参数让其从小到大排序
q.push(p(0, start_point));//起点进入
while (!q.empty()) {
p temp_p = q.top();//获得队首元素,也即是距离起点的最小值
q.pop();
int pos = temp_p.second;
if (dis_from_sp[pos] < temp_p.first)//这说明有可能这个点通过其他的中间点获得了比它记录的到起点的更短距离,这时候以它来更新最短距离没有意义(本来就不是最短的)
continue;
for (int i = 0; i < (int)e[pos].size(); i++) {//在pos能到达的点之间更新
edges new_edge = e[pos][i];
if (dis_from_sp[new_edge.to] > dis_from_sp[pos] + new_edge.diss) {//如果某个点距离起点的距离比通过中间点的连接的距离大,则要更新
dis_from_sp[new_edge.to] = dis_from_sp[pos] + new_edge.diss;
q.push(p(dis_from_sp[new_edge.to], new_edge.to));//这就相当于没有优化的Dijkstra算法中的dis_from_sp的更新
}
}
}
return dis_from_sp[end_point];
}
int main() {
std::ios::sync_with_stdio(false);
int case_num, n, dis;
string temp_f, temp_t;
cin >> case_num;
while (case_num--) {
cin >> n;
total_num_of_name = 0;
map<string, int> m;
for (int i = 0; i < MAX; i++) {//丫的没有初始化WA了n次
e[i].clear();
}
while (n--) {
cin >> temp_f >> temp_t >> dis;
if (m.find(temp_f) == m.end()) {
m[temp_f] = total_num_of_name++;
}
if (m.find(temp_t) == m.end()) {
m[temp_t] = total_num_of_name++;
}
e[m[temp_f]].push_back(edges(m[temp_t], dis));
e[m[temp_t]].push_back(edges(m[temp_f], dis));
}
for (int i = 0; i < total_num_of_name; i++) {//这里是对起点终点相同的点的调整,感觉不要也行吧。。。
int j;
for (j = 0; j < (int)e[i].size(); j++) {
if (e[i][j].to == i) {
e[i][j] = edges(i, 0);
break;
}
}
if (j >= (int)e[i].size())
e[i].push_back(edges(i, 0));
}
cin >> temp_f >> temp_t;
if (temp_f == temp_t) {
cout << 0 << endl;
continue;
}
if (m.find(temp_f) == m.end() || m.find(temp_t) == m.end()) {
cout << -1 << endl;
continue;
}
int ans = Dijkstra(m[temp_f], m[temp_t]);
cout << (ans < INF ? ans : -1) << endl;
}
return 0;
}
下面是自己的玩玩:如何还原最短路径呢?
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 99999999
#define MAX 115 * 2
//这次也是Dijkstra算法,但是在数值的插入和取最小值方面进行了优化,使用了优先队列,这样经过自动排序后,每次可以直接从队首取得距离起点最小值
int total_num_of_name;//点的总数
struct edges {//用结构体作为二维动态数组的元素存图
int to;//到达的点
int diss;//距离
edges(int new_to, int new_diss): to(new_to), diss(new_diss){}//结构体的初始化函数
};
vector<edges> e[MAX];//用结构体作为二维动态数组的元素存图
typedef pair<int, int> p;//优先队列里的元素,first是到起点距离,second是点号
int pre[MAX];
int Dijkstra(int start_point, int end_point) {
int dis_from_sp[MAX];//到起点的距离
fill(dis_from_sp, dis_from_sp + total_num_of_name, INF);//初始化
dis_from_sp[start_point] = 0;//起点的特殊处理
priority_queue<p, vector<p>, greater<p> > q;//优先队列,greater参数让其从小到大排序
q.push(p(0, start_point));//起点进入
fill(pre, pre + total_num_of_name, -1);
while (!q.empty()) {
p temp_p = q.top();//获得队首元素,也即是距离起点的最小值
q.pop();
int pos = temp_p.second;
if (dis_from_sp[pos] < temp_p.first)//这说明有可能这个点通过其他的中间点获得了比它记录的到起点的更短距离,这时候以它来更新最短距离没有意义(本来就不是最短的)
continue;
for (int i = 0; i < (int)e[pos].size(); i++) {//在pos能到达的点之间更新
edges new_edge = e[pos][i];
if (dis_from_sp[new_edge.to] > dis_from_sp[pos] + new_edge.diss) {//如果某个点距离起点的距离比通过中间点的连接的距离大,则要更新
dis_from_sp[new_edge.to] = dis_from_sp[pos] + new_edge.diss;
q.push(p(dis_from_sp[new_edge.to], new_edge.to));//这就相当于没有优化的Dijkstra算法中的dis_from_sp的更新
pre[new_edge.to] = pos;//这里表示,直接到达new_edge.to的最短路径上的点
}
}
}
return dis_from_sp[end_point];
}
string name[MAX];//用来存点的字符名字
void find_shortest_path(int p) {
vector<int> path;
for (; p != -1; p = pre[p])
path.push_back(p);//从终点不断地往回找
reverse(path.begin(), path.end());//倒过来就是从起点到终点了
vector<int> :: iterator pathh;
for (pathh = path.begin(); pathh != path.end(); pathh++) {
if (pathh != path.begin())
cout << " ---> ";
cout << name[*pathh];
}
cout << endl;
}
int main() {
std::ios::sync_with_stdio(false);
int case_num, n, dis;
string temp_f, temp_t;
cin >> case_num;
while (case_num--) {
cin >> n;
total_num_of_name = 0;
map<string, int> m;
for (int i = 0; i < MAX; i++) {//丫的没有初始化WA了n次
e[i].clear();
name[i].clear();
}
while (n--) {
cin >> temp_f >> temp_t >> dis;
if (m.find(temp_f) == m.end()) {
m[temp_f] = total_num_of_name++;
name[total_num_of_name - 1] = temp_f;
}
if (m.find(temp_t) == m.end()) {
m[temp_t] = total_num_of_name++;
name[total_num_of_name - 1] = temp_t;
}
e[m[temp_f]].push_back(edges(m[temp_t], dis));
e[m[temp_t]].push_back(edges(m[temp_f], dis));
}
for (int i = 0; i < total_num_of_name; i++) {//这里是对起点终点相同的点的调整,感觉不要也行吧。。。
int j;
for (j = 0; j < (int)e[i].size(); j++) {
if (e[i][j].to == i) {
e[i][j] = edges(i, 0);
break;
}
}
if (j >= (int)e[i].size())
e[i].push_back(edges(i, 0));
}
cin >> temp_f >> temp_t;
if (temp_f == temp_t) {
cout << 0 << endl;
continue;
}
if (m.find(temp_f) == m.end() || m.find(temp_t) == m.end()) {
cout << -1 << endl;
continue;
}
int ans = Dijkstra(m[temp_f], m[temp_t]);
cout << (ans < INF ? ans : -1) << endl;
find_shortest_path(m[temp_t]);
}
return 0;
}