进阶图论(最短路系列)

题目狂刷

P3371 【模板】单源最短路径(弱化版)

https://www.luogu.com.cn/problem/P3371

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;
using u32 = unsigned;
#define i128 __int128;
using ll = long long;
//#define int ll
using u64 = unsigned long long;
const ll inf = 1e9;
const ll INF = 1e18;
struct edge
{
int v,w;
};
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,s;
cin>>n>>m>>s;
vector<vector<edge>>adj(n+1);
vector<int>dis(n+1,INT_MAX);//注意这里不要使用1e9,直接使用INI_MAX就行
vector<bool>vis(n+1);
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
adj[u].push_back({v,w});
}
dis[s]=0;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>>pq;
pq.push({0,s});
while(pq.size())
{
auto [_,u]=pq.top();
pq.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:adj[u])
{
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pq.push({dis[v],v});
}
}
}
for(int i=1;i<=n;i++)cout<<dis[i]<<" \n"[i==n];
return 0;
}

P4779 【模板】单源最短路径(标准版)

https://www.luogu.com.cn/problem/P4779

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;
using u32 = unsigned;
#define i128 __int128;
using ll = long long;
//#define int ll
using u64 = unsigned long long;
const ll inf = 1e9;
const ll INF = 1e18;
struct edge
{
int v,w;
};
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,s;
cin>>n>>m>>s;
vector<vector<edge>>adj(n+1);
vector<int>dis(n+1,INT_MAX);
vector<bool>vis(n+1);
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
adj[u].push_back({v,w});
}
dis[s]=0;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>>pq;
pq.push({0,s});
while(pq.size())
{
auto [_,u]=pq.top();
pq.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:adj[u])
{
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pq.push({dis[v],v});
}
}
}
for(int i=1;i<=n;i++)cout<<dis[i]<<" \n"[i==n];
return 0;
}

C. Dijkstra?

https://codeforces.com/problemset/problem/20/C

这一道题一直内存超,最后修改了不让v重复入队。这个好像不是set,还是可以重复入队的。

这个pair<int,int>修改的也十分到位,感觉这个很好用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<bits/stdc++.h>
using namespace std;
using u32 = unsigned;
#define i128 __int128;
using ll = long long;
//#define int ll
using u64 = unsigned long long;
const ll inf = 1e9;
const ll INF = 1e18;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
vector<vector<pair<int,int>>>adj(n+1);
vector<bool>vis(n+1);
vector<int>dis(n+1,INT_MAX);
dis[1]=0;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
adj[u].emplace_back(v,w);
adj[v].emplace_back(u,w);
}
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>>pq;
pq.push({0,1});
vector<int>fa(n+1);
while(pq.size())
{
auto [_,u]=pq.top();
pq.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:adj[u])
{
if(vis[v])continue;
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
fa[v]=u;
pq.push({dis[v],v});
}
}
}
vector<int>ans;
if(dis[n]==INT_MAX)cout<<-1<<'\n';
else
{
auto dfs=[&](auto self,int x)->void{
if(x==1){cout<<1<<' ';return;}
self(self,fa[x]);
cout<<x<<' ';
};
dfs(dfs,n);
}


return 0;
}

P1576 最小花费

https://www.luogu.com.cn/problem/P1576

这一题其实考验的是最长路,这一题其实要求的就是从A到B所消耗的比例最少的路径,我们走的所有路径最终的结果是1*所有得比例,这个结果越大越好,就是最长路。然后就是路径中得加法运算变成乘法运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<bits/stdc++.h>
using namespace std;
using u32 = unsigned;
#define i128 __int128;
using ll = long long;
//#define int ll
using u64 = unsigned long long;
const ll inf = 1e9;
const ll INF = 1e18;

signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
vector<vector<pair<int,double>>>adj(n+1);
vector<double>bei(n+1,-inf);

for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
double it=(double)(100-w)/100;
adj[u].emplace_back(v,it);
adj[v].emplace_back(u,it);
}
int a,b;
cin>>a>>b;
bei[a]=1;
priority_queue<pair<double,int>>pq;
pq.push({1,a});
vector<int>vis(n+1);
while(pq.size())
{
auto [bi,u]=pq.top();
pq.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:adj[u])
{
if(bei[u]*w>bei[v])
{
bei[v]=bei[u]*w;
pq.push({bei[v],v});
}
}
}
cout<<fixed<<setprecision(8)<<100/bei[b]<<'\n';


return 0;
}

P5767 [NOI1997] 最优乘车

https://www.luogu.com.cn/problem/P5767

这道题学会一个好东西

std::ws 是 C++ 标准库中的一个输入流操作符,用于跳过输入流中的所有空白字符(包括空格、制表符和换行符),直到遇到非空白字符为止。

这道题中为了消除行末的空白字符需要用这个,洛谷这道题好像是行末有两个空白字符还是什么情况,快给我卡死了。

1
2
3
4
//必须得这样才能跳
char ch;
cin.get(ch);
cin.get(ch);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>
using namespace std;
using u32 = unsigned;
#define i128 __int128;
using ll = long long;
// #define int ll
using u64 = unsigned long long;
const ll inf = 1e9;
const ll INF = 1e18;

signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m, n;
cin >> m >> n;
char ch;
cin>>ws;
vector<vector<pair<int, int>>> adj(n + 1);
vector<bool> vis(n + 1);
vector<int> dis(n + 1, inf);
dis[1] = 0;
for (int i = 1; i <= m; i++)
{
vector<int> a;
string s;
getline(cin,s);
for(int i=0;i<s.size();i++)
{
int x=0;
while(isdigit(s[i]))
{
x=x*10+s[i]-'0';
i++;
}
a.push_back(x);
}
for(int i=0;i<a.size();i++)
{
for(int j=i+1;j<a.size();j++)
{
adj[a[i]].push_back({a[j],1});
}
}

}
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
pq.push({0, 1});
while (pq.size())
{
auto [_, u] = pq.top();
pq.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto [v, w] : adj[u])
{
if (vis[v] == 0 && dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
pq.push({dis[v], v});
}
}
}
if (dis[n] == inf)
cout << "NO\n";
else
cout << dis[n] - 1 << '\n';
return 0;
}