内容为武汉大学国家网络安全学院2022级大一第三学期“996”实训课程中所做的笔记,仅供个人复习使用,如有侵权请联系本人,将于15个工作日内将博客设置为仅粉丝可见。
骑车比赛
- 时间限制:1000ms
- 内存限制:131072K
- 语言限制:C语言
蒜头君准备去参加骑车比赛,比赛在 n 个城市间进行,编号从 1 到 n。选手们都从城市 1 出发,终点在城市 n。
已知城市间有 m 条道路,每条道路连接两个城市,注意道路是双向的。现在蒜头君知道了他经过每条道路需要花费的时间,他想请你帮他计算一下,他这次比赛最少需要花多少时间完成。
输入格式
第一行输入两个整数 n,m(1≤n≤1,000,1≤m≤5,000),分别代表城市个数和道路总数。接下来输入 m 行,每行输入三个数字 a,b,c(1≤a,b≤n,1≤c≤200),分别代表道路的起点和道路的终点,以及蒜头君骑车通过这条道路需要花费的时间。保证输入的图是连通的。
输出格式
输出一行,输出一个整数,输出蒜头君完成比赛需要的最少时间。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
5 6
1 2 2
2 3 3
2 5 5
3 4 2
3 5 1
4 5 1
样例输出
6
我的答案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 1005
#define INF 0x3f3f3f3f
int n, m;
int g[MAXN][MAXN];
int dist[MAXN];
int vis[MAXN];
void dijkstra(int s) {
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0;
for (int i = 1; i <= n; i++) {
int x = 0;
for (int j = 1; j <= n; j++) {
if (!vis[j] && (x == 0 || dist[j] < dist[x])) {
x = j;
}
}
vis[x] = 1;
for (int y = 1; y <= n; y++) {
dist[y] = dist[y] < dist[x] + g[x][y] ? dist[y] : dist[x] + g[x][y];
}
}
}
int main() {
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof(g));
while (m--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = c;
}
dijkstra(1);
printf("%d\n", dist[n]);
return 0;
}
迷阵突围(Day10 完成)
- 时间限制:1000ms
- 内存限制:131072K
- 语言限制:C语言
蒜头君陷入了坐标系上的一个迷阵,迷阵上有 n 个点,编号从 1 到 n。蒜头君在编号为 1 的位置,他想到编号为 n 的位置上。蒜头君当然想尽快到达目的地,但是他觉得最短的路径可能有风险,所以他会选择第二短的路径。现在蒜头君知道了 n 个点的坐标,以及哪些点之间是相连的,他想知道第二短的路径长度是多少。
注意,每条路径上不能重复经过同一个点。
输入格式
第一行输入两个整数 n(1≤n≤200) 和 m,表示一共有 n 个点和 m 条边。
接下来输入 n 行,每行输入两个整数 x_i,y_i(−500≤x_i,y_i≤500),代表第 i 个点的坐标。
接下来输入 m 行,每行输入两个整数 p_j,q_j (1≤p_j,q_j≤n),表示点 p_j 和点 q_j 之间相连。
输出格式
输出一行,输出包含一个数,表示第二短的路径长度(小数点后面保留两位),如果第一短路径有多条,则答案就是第一最短路径的长度;如果第二最短路径不存在,则输出 −1。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
3 3
1 1
2 2
3 2
1 2
2 3
1 3
样例输出
2.41
题解:先求出一条最短路径,依次枚举上面的每条边删除,然后依次求最短路,并得到其中的最小值。
我的答案
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
#define N 210
#define M 40100
struct edge {
int v, next, f;
double w;
} e[M];
int p[N], eid;
int pre[N];
double d[N];
int x[N], y[N];
int vis[N];
int n, m;
void init() {
memset(p, -1, sizeof(p));
eid = 0;
}
void insert(int u, int v, double w) {
e[eid].v = v;
e[eid].w = w;
e[eid].next = p[u];
e[eid].f = 1;
p[u] = eid++;
}
double dis(int i, int j) {
return sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
}
void dijkstra(int s, int del) {
int i, j, u, v;
double min, w;
for(i=1; i<=n; i++) {
d[i] = INF;
vis[i] = 0;
pre[i] = -1;
}
d[s] = 0;
for(i=1; i<=n; i++) {
min = INF;
u = -1;
for(j=1; j<=n; j++) {
if(!vis[j] && d[j]<min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = 1;
for(j=p[u]; j!=-1; j=e[j].next) {
if(j == del || j == (del^1)) continue;
v = e[j].v;
w = e[j].w;
if(!vis[v] && d[v]>d[u]+w) {
d[v] = d[u] + w;
pre[v] = j;
}
}
}
}
int main() {
int i, u, v;
double ans, tmp;
scanf("%d%d", &n, &m);
init();
for(i=1; i<=n; i++) {
scanf("%d%d", &x[i], &y[i]);
}
for(i=0; i<m; i++) {
scanf("%d%d", &u, &v);
insert(u, v, dis(u, v));
insert(v, u, dis(u, v));
}
ans = INF;
dijkstra(1, -1);
for(i=pre[n]; i!=-1; i=pre[e[i^1].v]) {
tmp = e[i].w;
e[i].w = e[i^1].w = INF;
dijkstra(1, -1);
if(d[n] < ans) ans = d[n];
e[i].w = e[i^1].w = tmp;
}
if(ans == INF) printf("-1\n");
else printf("%.2lf\n", ans);
return 0;
}