最短路
算法讲解
spfa
个人曾经是个巨菜巨菜的oier,所以对又好写,又不用管负权圈的spfa情有独钟,所以导致到现在写最短路还都是用的spfa。因为有的时候vector实在太慢了,所以我就把邻接表打了个包~这样用着舒服一点。
普通spfa
关于spfa的原理啥的,别的大佬们写的太好了,我就不献丑了~这里还是推荐一个大佬的spfa原理讲解~
ps:虽然各路大佬都在声讨spfa的复杂度很差,常数很高啥的,但是架不住好写哇orz。各路大佬轻喷啊~
模板
class short_road {
protected:
private:
struct rec {
int u, v, next;
int w;
} edge[maxn];
bool vis[maxn];
int dis[maxn];
int cnt[maxn], head[maxn];
int tot,n;
public:
inline void init(int _n) {
tot = 0;
clr(edge);
cld(head);
clr(vis);
clx(dis);
clr(cnt);
n = _n;
}
inline void Addedge(int u, int v, int w) {
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot;
tot++;
}
inline bool relax(rec e) {
if (dis[e.u] + e.w < dis[e.v]) {
dis[e.v] = dis[e.u] + e.w;
return true;
} else {
return false;
}
}
inline bool spfa(int x) {
queue<int> data;
data.push(x);
dis[x] = 0;
vis[x] = true;
cnt[x]++;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = head[u]; i != -1; i = edge[i].next) {
rec e = edge[i];
if (relax(e)) {
if (++cnt[e.v] > n) return true;
if (!vis[e.v]) {
vis[e.v] = true;
data.push(e.v);
}
}
}
}
return false;
}
inline int dist(int t){
return dis[t];
}
} sr;
SLF和LLF优化
说spfa肯定要说两个优化啦~有的时候又要有负权圈,又要快,就只能用SLF和LLF两种优化啦~不过如果没有负权圈,但是普通spfa不能过的话,就别用这两个优化了,直接dijkstra就完了~像上次qls出的女生赛题,不管你spfa再怎么优化也都过不了,只能稳稳妥妥写dijkstra咯~
再说两种优化:
SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。
LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。 SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。
模板
class short_road {
protected:
private:
struct rec {
int v, next, cap;
} edge[maxn];
int len,n;
int dis[maxn / 4], head[maxn / 4], cnt[maxn / 4];
bool vis[maxn / 4];
public:
inline void init(int _n) {
clr(edge);
cld(head);
clx(dis);
clr(vis);
clr(cnt);
len = 0;
n = _n;
}
inline void Addedge(int from, int to, int cap) {
edge[len].v = to;
edge[len].cap = cap;
edge[len].next = head[from];
head[from] = len++;
}
inline bool spfa(int s) {
dis[s] = 0;
vis[s] = true;
deque<int> que;
que.push_front(s);
while (!que.empty()) {
int k = que.front();
que.pop_front();
vis[k] = false;
cnt[k]++;
if (cnt[k] > n) return false;
for (int i = head[k]; i != -1; i = edge[i].next) {
if (dis[edge[i].v] > dis[k] + edge[i].cap) {
dis[edge[i].v] = dis[k] + edge[i].cap;
if (que.empty()) {
que.push_front(edge[i].v);
vis[edge[i].v] = true;
} else if (!vis[edge[i].v]) {
if (dis[edge[i].v] > dis[que.front()]) {
que.push_back(edge[i].v);
} else {
que.push_front(edge[i].v);
}
vis[edge[i].v] = true;
}
}
}
}
return true;
}
inline int dist(int t){
return dis[t];
}
} sr;
dijkstra
虽然喜欢用spfa,但是dijkstra还是肯定要会的啦,毕竟有些毒瘤出题人就很喜欢卡spfa是吧~算法原理我就不写了,这里按照惯例还是推荐一篇大佬写的dijkstra算法原理
当然啦~dijkstra的模板还是要贴一下的(肯定是优先队列优化的,非优化的我就不说了)。
模板
class short_road {
protected:
private:
struct rec {
int v, w;
explicit rec(int _v = 0, int _w = 0) {
v = _v;
w = _w;
}
bool operator<(const rec &a) const {
if (w == a.w) return v < a.v;
else return w < a.w;
}
};
struct rec1 {
int u, v, next;
int w;
} edge[maxn];
int dis[maxn], n,tot,head[maxn];
public:
inline void init(int _n) {
tot = 0;
clr(edge);
cld(head);
clx(dis);
n = _n;
}
inline void Addedge(int u, int v, int w) {
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot;
tot++;
}
inline bool relax(rec1 e) {
if (dis[e.u] + e.w < dis[e.v]) {
dis[e.v] = dis[e.u] + e.w;
return true;
} else {
return false;
}
}
inline void Dijkstra(int s) {
dis[s] = 0;
priority_queue<rec> q;
q.push(rec(s, dis[s]));
while (!q.empty()) {
rec u = q.top();
q.pop();
for (int i = head[u.v]; i != -1; i = edge[i].next) {
rec1 e = edge[i];
if (relax(e)) {
q.push(rec(e.v, dis[e.w]));
}
}
}
}
inline int dist(int t) {
return dis[t];
}
} sr;
题解
又到了喜闻乐见的kuangbin系列题解了~
POJ - 2387 Til the Cows Come Home
传送门:POJ - 2387
题意
有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离。
题解
直接单源最短路跑就ok了~模板题~
ps:dijkstra要判重边,但spfa就不用,也许这就是我这个菜鸡为毛爱用spfa吧
ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e4 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
struct rec {
int v;
int w;
rec(int _v, int _w) {
v = _v;
w = _w;
}
};
vector<rec> vec[maxn];
bool vis[maxn];
int dis[maxn];
int n, t, u, v, w;
void spfa(int x) {
clr(vis);
for (int i = 1; i <= n; ++i) {
dis[i] = inf;
}
queue<int> data;
data.push(x);
dis[x] = 0;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
int w = vec[u][i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (~scanf("%d%d", &t, &n)) {
clr(vec);
for (int i = 0; i < t; i++) {
scanf("%d%d%d", &u, &v, &w);
vec[u].push_back(rec(v, w));
vec[v].push_back(rec(u, w));
}
spfa(1);
printf("%d\n", dis[n]);
}
return 0;
}
POJ - 2253 Frogger
传送门:POJ - 2253
题意
有一条小河,河中有青蛙a和青蛙b。青蛙a呆在石头1上,青蛙b呆在石头2上,已知河中总共有n块石头,编号为1~n,已知所有石头的坐标。现在青蛙a想去找青蛙b玩,求青蛙a所需的最小跳跃距离。
题解
就把所有的两点之间距离求一下就ok了~然后直接跑最短路就ok了~
ac代码
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));
int n;
double dis[maxn];
int vis[maxn];
struct rec {
int x, y;
} a[maxn];
double distance1(int x, int y) {
int p = abs(a[x].x - a[y].x);
int q = abs(a[x].y - a[y].y);
return sqrt((double) p * p + q * q);
}
void spfa(int x) {
clr(vis);
for (int i = 1; i <= n; i++) {
dis[i] = inf;
}
queue<int> data;
dis[x] = 0;
data.push(x);
while (!data.empty()) {
int u = data.front();
vis[u] = false;
data.pop();
for (int i = 1; i <= n; i++) {
if (i != u) {
if (dis[i] > max(dis[u], distance1(u, i))) {
dis[i] = max(dis[u], distance1(u, i));
if (!vis[i]) {
vis[i] = true;
data.push(i);
}
}
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int num = 0;
while (~scanf("%d", &n) && n) {
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
}
spfa(1);
printf("Scenario #%d\n", ++num);
printf("Frog Distance = %.3lf\n", dis[2]);
cout << endl;
}
return 0;
}
POJ - 1797 Heavy Transportation
传送门: POJ - 1797
题意
有n个城市,m条道路,在每条道路上有一个承载量,现在要求从1到n城市最大承载量,而最大承载量就是从城市1到城市n所有通路上的最大承载量
题解
还是最短路的模板,就是改成求最大化最小值~那就把板子一套,完活~
ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e5 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));
struct rec {
int v, w;
rec(int _v, int _w) {
v = _v;
w = _w;
}
};
vector<rec> vec[maxn];
bool vis[maxn];
int dis[maxn];
int n, m, u, v, w;
void spfa(int x) {
clr(vis);
clr(dis);
queue<int> data;
data.push(x);
dis[1] = inf;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
int w = vec[u][i].w;
if (dis[v] < min(dis[u], w)) {
dis[v] = min(dis[u], w);
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int T;
scanf("%d",&T);
int num = 0;
while (T--) {
clr(vec);
scanf("%d%d",&n,&m);
while (m--) {
scanf("%d%d%d",&u,&v,&w);
vec[u].push_back(rec(v, w));
vec[v].push_back(rec(u, w));
}
spfa(1);
printf("Scenario #%d:\n%d\n\n",++num,dis[n]);
}
return 0;
}
POJ - 3268 Silver Cow Party
传送门:POJ - 3268
题意
有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。
题解
去和返回,求两次,返回好求,直接用目标牛跑spfa。去咋求呢,就可以直接把所有边全部反过来建图,然后还是用目标牛跑spfa,这样就求出来每头牛到目标牛的最短路啦~
ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6+7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));
struct rec {
int v;
int w;
rec(int _v = 0, int _w = 0) {
v = _v;
w = _w;
}
};
vector <rec> vec1[maxn];
vector<rec> vec2[maxn];
bool vis[maxn];
int dis1[maxn],dis2[maxn];
int n,m,x,a,b,t;
void spfa(int x,int dis[],vector<rec> vec[]) {
clr(vis);
for (int i = 1; i <= n; ++i) {
dis[i] = inf;
}
queue<int> data;
data.push(x);
dis[x] = 0;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
int w = vec[u][i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
cin >> n >> m >> x;
for(int i = 0;i < m;i++){
cin >> a >> b >> t;
vec1[b].push_back(rec(a,t));
vec2[a].push_back(rec(b,t));
}
spfa(x,dis1,vec1);
spfa(x,dis2,vec2);
int ans = -inf;
for(int i = 1;i <= n;i++){
ans = max(dis1[i] + dis2[i],ans);
}
cout << ans<< endl;
return 0;
}
POJ - 1860 Currency Exchange
传送门:POJ - 1860
题意
给定N种货币,某些货币之间可以相互兑换,现在给定一些兑换规则,问能否从某一种货币开始兑换,经过一些中间货币之后,最后兑换回这种货币,并且得到的钱比之前的多。
题解
这题很明显就是spfa判断负环,也不能叫负环哈,就是求最长路,然后判断正环,直接spfa模板一套,完事。
ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
struct rec {
int v;
double r, c;
explicit rec(int _v = 0, double _r = 0, double _c = 0) {
v = _v;
r = _r;
c = _c;
}
};
vector<rec> vec[maxn];
bool vis[maxn];
double dis[maxn];
int cnt[maxn];
int n, m, s;
bool spfa(int x, double mon) {
clr(vis);
clr(dis);
queue<int> data;
data.push(x);
for (int i = 0; i < n + 1; i++) {
dis[i] = -inf;
}
dis[x] = mon;
cnt[x]++;
vis[x] = true;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
double w = (dis[u] - vec[u][i].c) * vec[u][i].r;
if (dis[v] < w) {
dis[v] = w;
cnt[v]++;
if (cnt[v] > n) return false;
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
return true;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
double v;
int a, b;
double rab, cab, rba, cba;
cin >> n >> m >> s >> v;
for (int i = 0; i < m; i++) {
cin >> a >> b >> rab >> cab >> rba >> cba;
vec[a].emplace_back(rec(b, rab, cab));
vec[b].emplace_back(rec(a, rba, cba));
}
if (spfa(s, v)) {
cout << "NO" << endl;
} else {
cout << "YES" << endl;
}
return 0;
}
POJ - 3259 Wormholes
传送门:POJ - 3259
题意
这题问是否能通过虫洞回到过去。
虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。
题解
这题同上题,也是spfa跑负权圈
ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
struct rec {
int v, w;
explicit rec(int _v = 0, int _w = 0) {
v = _v;
w = _w;
}
};
bool vis[maxn];
int dis[maxn], cnt[maxn];
vector<rec> vec[maxn];
int n, m, w, u, v, t;
bool spfa(int x) {
clr(vis);
clr(dis);
clr(cnt);
for (int i = 0; i <= n; i++) {
dis[i] = inf;
}
queue<int> data;
data.push(x);
vis[x] = true;
dis[x] = 0;
cnt[x]++;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
int w = vec[u][i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (++cnt[v] > n - 1) {
return false;
}
if (!vis[v]) {
data.push(v);
vis[v] = true;
}
}
}
}
return true;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--) {
clr(vec);
cin >> n >> m >> w;
for (int i = 0; i < m; i++) {
cin >> u >> v >> t;
vec[u].emplace_back(rec(v, t));
vec[v].emplace_back(rec(u, t));
}
for (int i = 0; i < w; i++) {
cin >> u >> v >> t;
vec[u].emplace_back(rec(v, -t));
}
if (!spfa(1)) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
return 0;
}
POJ - 1502 MPI Maelstrom
传送门:POJ - 1502
题意
N个处理器要进行信息传递,处理器i传递信息给自己不需要时间,处理器i与处理器j之间相互传递信息的时间是一样的,不同处理器之间传递信息所需要的时间由一个矩阵的下三角给出。若矩阵对应位置为x,则说明相应的两个处理器之间无法传递信息。求从第一个处理器传递信息到其他所有处理器最少需要多少时间。
题解
这个就是直接的最短路,只要处理一下读入就ok了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e3;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
struct rec {
int v, w;
rec(int _v, int _w) {
v = _v;
w = _w;
}
};
vector<rec> vec[maxn];
bool vis[maxn];
int dis[maxn];
int n, m, u, v, w;
void spfa(int x) {
clr(vis);
clr(dis);
for(int i = 0;i <= n;i++){
dis[i] = inf;
}
queue<int> data;
data.push(x);
dis[x] = 0;
vis[x] = true;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int i = 0; i < vec[u].size(); ++i) {
int v = vec[u][i].v;
int w = vec[u][i].w;
if (dis[v] > dis[u]+ w) {
dis[v] = dis[u]+ w;
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
cin >> n;
string ch;
for(int i = 2;i <= n;i++){
for(int j = 1;j < i;j++){
cin >> ch;
if(ch != "x"){
int w = atoi(ch.c_str());
vec[i].push_back(rec(j,w));
vec[j].push_back(rec(i,w));
}
}
}
spfa(1);
int ans = 0;
for(int i = 1;i <= n;i++){
ans = max(ans,dis[i]);
}
cout << ans << endl;
return 0;
}
POJ - 3660 Cow Contest
传送门:POJ - 3660
题意
有n头牛比赛,m种比赛结果,最后问你一共有多少头牛的排名被确定了,其中如果a战胜b,b战胜c,则也可以说a战胜c,即可以传递胜负。求能确定排名的牛的数目。
题解
这题就是传递闭包了,
G的传递闭包定义为G*=(V,E*),其中E={(i,j):图G中存在一条从i到j的路径}。
直接看代码吧~
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
int mp[105][105];
int n,m;
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (~scanf("%d%d", &n, &m)) {
int u, v;
memset(mp, 0, sizeof(mp));
for (int i = 0; i < m; i++) {
scanf("%d %d", &u, &v);
mp[u][v] = 1;
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
mp[i][j] = (mp[i][j] | (mp[i][k] & mp[k][j]));
}
}
}
for (int i = 1; i <= n; i++) mp[i][i] = 0;
int ans = 0;
for (int i = 1; i <= n; i++) {
int cnt = 0;
for (int j = 1; j <= n; j++) {
cnt += mp[i][j];
cnt += mp[j][i];
}
if (cnt == n - 1) ans++;
}
printf("%d\n", ans);
}
return 0;
}
POJ - 2240 Arbitrage
传送门:POJ - 2240
题意
已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加。
题解
这题和上面POJ - 1860几乎一样,也是spfa判断负权圈
ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e4;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
string a[maxn];
int n, m;
int check(const string &str) {
for (int i = 1; i <= n; i++) {
if (str == a[i]) {
return i;
}
}
}
class short_road {
protected:
private:
struct Edge {
int u, v, next;
double w;
} edge[maxn];
bool vis[maxn];
double dis[maxn];
int cnt[maxn], head[maxn];
int tot;
public:
inline void init() {
tot = 0;
clr(edge);
memset(head, -1, sizeof(head));
}
inline void addEdge(int u, int v, double w) {
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot;
tot++;
}
inline bool relax(int e) {
if (dis[edge[e].u] * edge[e].w > dis[edge[e].v]) {
dis[edge[e].v] = dis[edge[e].u] * edge[e].w;
return true;
} else {
return false;
}
}
inline bool spfa(int x) {
clr(vis);
clr(dis);
clr(cnt);
queue<int> data;
data.push(x);
dis[x] = 1;
vis[x] = true;
cnt[x]++;
while (!data.empty()) {
int u = data.front();
data.pop();
vis[u] = false;
for (int e = head[u]; e != -1; e = edge[e].next) {
if (relax(e)) {
if (++cnt[edge[e].v] > n) return true;
if (!vis[edge[e].v]) {
vis[edge[e].v] = true;
data.push(edge[e].v);
}
}
}
}
return false;
}
} sr;
int main() {
//std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int T = 0;
while (~scanf("%d", &n) && n) {
for (int i = 1; i <= n; i++) {
cin >> a[i];
sr.init();
}
string str1, str2;
double w;
cin >> m;
for (int i = 0; i < m; i++) {
cin >> str1 >> w >> str2;
sr.addEdge(check(str1), check(str2), w);
}
if (sr.spfa(1)) {
printf("Case %d: Yes\n", ++T);
} else {
printf("Case %d: No\n", ++T);
}
}
return 0;
}
CSU - 1808 地铁
传送门:CSU - 1808
题意
中文题我题意就不写了啊~
题解
这个题是真的很有意思呀~
这个题有很多种写法,有拆边写的,有优先队列加bfs(总觉得就是写了个spfa),有加边的dijkstra,各种写法都有。
我自己是用map做映射写的,还是很有意思的题~
ps:我这个写法确实有点慢,应该是这些写法里最慢得了。
ac代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <ctime>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mxll = 0x3f3f3f3f3f3f3f3f;
const int maxn = (int) 4e5 + 7;
const double eps = 1e-10;
const ll mod = (int) 1e9 + 7;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define clr(x) memset(x,0,sizeof(x))
#define clx(x) memset(x,63,sizeof(x))
#define cln(x) memset(x,-64,sizeof(x))
#define pi 3.1415926
struct rec {
ll v, w, c;
rec(ll _v, ll _w, ll _c) {
v = _v;
w = _w;
c = _c;
}
};
struct node {
ll w, id;
};
vector<rec> vec[maxn];
bool vis[maxn];
map<ll, ll> dis[maxn];
ll n, m, u, v, w, c;
void spfa(ll x) {
clr(vis);
for (int i = 0; i <= n; i++)dis[i].clear();
queue<ll> data;
data.push(x);
dis[x][0] = 0;
while (!data.empty()) {
ll u = data.front();
data.pop();
vis[u] = false;
for (auto &i : vec[u]) {
ll v = i.v;
ll w = 0;
for (auto &iter : dis[u]) {
if (u == x) {
w = i.w;
} else {
w = i.w + abs(iter.first - i.c);
}
if (dis[v][i.c] > w + iter.second || (dis[v][i.c] == 0 && v != x)) {
dis[v][i.c] = iter.second + w;
if (!vis[v]) {
vis[v] = true;
data.push(v);
}
}
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (~scanf("%lld%lld", &n, &m)) {
clr(vec);
for (int i = 0; i < m; i++) {
scanf("%lld%lld%lld%lld", &u, &v, &c, &w);
vec[u].emplace_back(rec(v, w, c));
vec[v].emplace_back(rec(u, w, c));
}
spfa(1);
ll ans = mxll;
for (auto &iter : dis[n]) {
ans = min(iter.second, ans);
}
printf("%lld\n", ans);
}
return 0;
}
小计
自己是真的懒。。。老早老早就写完的题,一直拖到这个时候才写博客orz。忘大家捧场啦~