最短路

单源最短路的建图方式

边权非负 dijkstra

有负权边 spfa

难度在于问题的转化和抽象(如何转化成最短路问题)

热浪(dijkstra模板)

#include <bits/stdc++.h>
using namespace std;
const int N = 2505;
int n, dis[N], m, s, e, vis[N];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w;}
};

vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX;
	dis[s] = 0;
	q.push((edge){s, 0});
	while(!q.empty())
	{
		edge x = q.top();
		q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d %d %d", &n, &m ,&s, &e);
	for (int i = 1; i <= m; ++ i) 
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
	}
	dijkstra();
	printf("%d", dis[e]);
	return 0;
}

信使

#include <bits/stdc++.h>
using namespace std;
const int N = 2505;
int n, dis[N], m, s, e, vis[N];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX;
	dis[s] = 0;
	q.push((edge){s, 0});
	while(!q.empty())
	{
		edge x = q.top();
		q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	s = 1;
	for (int i = 1; i <= m; ++ i) 
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
	}
	dijkstra();
	int ans = 0;
	for (int i = 1; i <= n; ++ i) ans = max(ans, dis[i]);
	if(ans == INT_MAX) ans = -1;
	printf("%d", ans);
	return 0;
}

香甜的黄油

暴力枚举每一个作为原点的答案

#include <bits/stdc++.h>
using namespace std;
const int N = 805;
int n, dis[N], vis[N], p, c, cow[N], ans = INT_MAX;
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int s)
{
	for (int i = 1; i <= p; ++ i) dis[i] = INT_MAX, vis[i] = 0;
	dis[s] = 0;
	q.push((edge){s, 0});
	while(!q.empty())
	{
		edge x = q.top();
		q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d %d", &n, &p, &c);
	for (int i = 1; i <= n; ++ i)
	{
		int x; scanf("%d", &x);
		cow[x] ++;
	}
	for (int i = 1; i <= c; ++ i)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
	}
	for (int i = 1; i <= p; ++ i)
	{
		dijkstra(i);
		int sum = 0;
		for (int j = 1; j <= p; ++ j) sum = sum + cow[j] * dis[j];
		ans = min(ans, sum);
	}
	printf("%d", ans);
	return 0;
}

最小花费

加法变成了乘法,但是本质没有什么区别

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int s, e, n, m;
typedef long double db;
db dis[N];
bool vis[N];
struct edge
{
	int v;
	db w;
	bool operator < (const edge &a) const {return w < a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int s)
{
	dis[s] = 1.0;
	q.push((edge){s, 1.0});
	while(!q.empty())
	{
		edge x = q.top();
		q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] < dis[x.v] * y.w)
			{
				dis[y.v] = dis[x.v] * y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; ++ i)
	{
		int u, v;
		db w;
		scanf("%d %d %Lf", &u, &v, &w);
		g[u].push_back((edge){v, 1.0 - w / 100.0});
		g[v].push_back((edge){u, 1.0 - w / 100.0});
	}
	scanf("%d %d", &s, &e);
	dijkstra(s);
	printf("%.8Lf", 100.0 / dis[e]);
	return 0;
}

最优乘车

#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int a[N], n, m, dis[N], vis[N];
vector<int> g[N];
string s;
void bfs()
{
	queue<int> q;
	dis[1] = 0;
	q.push(1);
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i];
			if(dis[y] > dis[x] + 1)
			{
				dis[y] = dis[x] + 1;
				q.push(y);
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &m, &n);
	getchar();
	for (int i = 1; i <= m; ++ i)
	{
		getline(std::cin, s);
		int x = 0, cnt = 0;
		for (int j = 0; j < s.length(); ++ j) 
		{
			if(s[j] >= '0' && s[j] <= '9') x = x * 10 + s[j] - '0';
			else a[++ cnt] = x, x = 0;
		}
		a[++ cnt] = x;
		for (x = 1; x <= cnt; ++ x)
		{
			for (int y = x + 1; y <= cnt; ++ y) g[a[x]].push_back(a[y]);
		}
	}
	for (int i = 1; i <= n; ++ i) dis[i] = 0x3f3f3f3f;
	bfs();
	if(dis[n] == 0x3f3f3f3f) printf("NO");
	else printf("%d", dis[n] - 1);
	return 0;
}

昂贵的聘礼

一个需要分段跑的最短路

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int d, n, dis[N], L[N];
bool vis[N];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N];

priority_queue<edge> q;
void dijkstra(int l, int r)
{
	for (int i = 0; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
	dis[0] = 0; q.push((edge){0, 0});
	while(!q.empty())
	{
		edge x = q.top(); q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(l <= L[y.v] && L[y.v] <= r && dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &d, &n);
	for (int i = 1; i <= n; ++ i)
	{
		int c, l, x;
		scanf("%d %d %d", &c, &L[i], &x);
		g[0].push_back((edge){i, c});
		for (int j = 1; j <= x; ++ j)
		{
			scanf("%d %d", &l, &c);
			g[l].push_back((edge){i, c});	
		} 
	}	
	int ans = INT_MAX;
	for (int i = L[1] - d; i <= L[1]; ++ i)
	{
		dijkstra(i, i + d);
		ans = min(ans, dis[1]);
	}
	printf("%d", ans);
}

单源最短路的综合应用

新年好

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dis[6][N], m;
bool vis[N];
pair<int, int> a[6];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int z, int s)
{
	for (int i = 0; i <= n; ++ i) vis[i] = 0, dis[z][i] = INT_MAX;
	dis[z][s] = 0; q.push((edge){s, 0});
	while(!q.empty())
	{
		edge x = q.top(); q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[z][y.v] > dis[z][x.v] + y.w)
			{
				dis[z][y.v] = dis[z][x.v] + y.w;
				q.push((edge){y.v, dis[z][y.v]});
			} 
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= 5; ++ i) scanf("%d", &a[i].first), a[i].second = i;
	for (int i = 1; i <= m; ++ i)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
	}
	dijkstra(0, 1);
	for (int i = 1; i <= 5; ++ i) dijkstra(a[i].second, a[i].first);
	sort(a + 1, a + 5 + 1);
	int ans = INT_MAX;
	do
	{
		int sum = dis[0][a[1].first];
		for (int i = 2; i <= 5; ++ i) sum += dis[a[i - 1].second][a[i].first];
		ans = min(ans, sum);
	}while(next_permutation(a + 1, a + 5 + 1));
	printf("%d", ans);
	return 0;
}

通信线路

二分判断就可以了。

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 10005;
int n, m, k;
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
int eu[M], ev[M], ew[M], dis[N];
bool vis[N];
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 0; i <= n; ++ i) vis[i] = 0, dis[i] = INT_MAX;
	dis[1] = 0; q.push((edge){1, 0});
	while(!q.empty())
	{
		edge x = q.top(); q.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				q.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
bool check(int x)
{
	for (int i = 1; i <= n; ++ i) g[i].clear();
	for (int i = 1; i <= m; ++ i)
	{
		int w = 1;
		if(ew[i] <= x) w = 0;
		g[eu[i]].push_back((edge){ev[i], w});
		g[ev[i]].push_back((edge){eu[i], w});
	}
	dijkstra();
	if(dis[n] <= k) return true;
	return false;
}
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%d%d%d", &eu[i], &ev[i], &ew[i]);
	}
	int l = 0, r = 1000000, mid, ans = INT_MAX;
	while(l <= r)
	{
		mid = l + r >> 1;
		if(check(mid)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	if(ans == INT_MAX) printf("-1");
	else printf("%d", ans);
	return 0;
}

道路与航线

1.如果所有边权非负,可以用Dijkstra,时间\(O(mlog_{n})\)

2.如果是拓扑图,不管边权为正为负,均可按拓扑序扫描,时间\(O(n)\)

因为题目中存在A -> B的航线就不存在B -> A的航线和道路,所以所有的道路可以变成一个团,并且团的内部一定没有航线。团与团之间一定存在拓扑序。

所以在每一个团内部用dijkstra,团与团之间用拓扑序来处理就可以了。

#include <bits/stdc++.h>
using namespace std;
const int N = 25005;
int n, dis[N], cnt = 0, R, P, S, fa[N], in[N];
bool vis[N], pd[N];
struct edge
{
	int v, w, u;
	bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N], p[N];
vector<int> z[N];
queue<int> q;
priority_queue<edge> h;
int findset(int x)
{
	if(fa[x] == x) return x;
	else return fa[x] = findset(fa[x]); 
}
void dijkstra(int s)
{
	for (int i = 0; i < z[s].size(); ++ i) h.push((edge){z[s][i], dis[z[s][i]]});
	while(!h.empty())
	{
		edge x = h.top();
		h.pop();
		if(vis[x.v]) continue;
		vis[x.v] = 1;
		for (int i = 0; i < g[x.v].size(); ++ i)
		{
			edge y = g[x.v][i];
			if(dis[y.v] > dis[x.v] + y.w)
			{
				dis[y.v] = dis[x.v] + y.w;
				h.push((edge){y.v, dis[y.v]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d %d %d", &n, &R, &P, &S);
	for (int i = 1; i <= n; ++ i) fa[i] = i;
	for (int i = 1; i <= R; ++ i)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
		u = findset(u), v = findset(v);
		if(u == v) continue;
		fa[u] = v;
	}
	for (int i = 1; i <= P; ++ i)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		p[findset(u)].push_back((edge){v, w, u});
		in[findset(v)] ++;
	}
	for (int i = 1 ; i <= n; ++ i) dis[i] = INT_MAX;
	int s = findset(S);
	dis[S] = 0, pd[s] = true;
	z[s].push_back(S);
	for (int i = 1; i <= n; ++ i)
	{
		if(i == findset(i) && !in[i]) q.push(i); 
	}
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		if(pd[x]) dijkstra(x);
		for (int i = 0; i < p[x].size(); ++ i)
		{
			int y = p[x][i].v;
			int fy = findset(y);
			if(dis[p[x][i].u] != INT_MAX && dis[y] > dis[p[x][i].u] + p[x][i].w) 
			{
				dis[y] = dis[p[x][i].u] + p[x][i].w;
				z[fy].push_back(y), pd[fy] = true;
			}
			in[fy] --;
			if(!in[fy]) q.push(fy);
		}
	}
	for (int i = 1; i <= n; ++ i)
	{
		if(dis[i] == INT_MAX) printf("NO PATH\n");
		else printf("%d\n", dis[i]);
	}
	return 0;
}

最优贸易

求出所有从1到i经过城市的买入的最小值\(dmin[i]\)

和所有从i走到n经过的城市中卖出的最大值\(dmax[i]\)

那么就能算出以i为分界的(包括i)赚取的最大价值为\(dmax[i] - dmin[i]\)

因为图中是有环形的,所以不能使用dp,可以转化成最短路问题。

能用dijkstra的核心就是将这个点从堆取出来的时候,这个点的最小值一定不会再被其它的节点更新了。(但是因为这个题目中有环,所以这个点取出来后可能被其它节点更新)

spfa算法的适用范围更加广泛。spfa算法和bellman_ford算法是等价的。其步骤是迭代n - 1(路径长度最多是n - 1)次,循环所有边,用三角不等式更新。只要路径的边数是小于等于n - 1的,bellman_ford算法就是正确的

代码一遍过!

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, a[N], m, ans = 0, dmin[N], dmax[N];
queue<int> q;
vector<int> g[N], f[N];
bool vis[N];
void spfamin()
{
	for (int i = 1; i <= n; ++ i) vis[i] = 0, dmin[i] = INT_MAX;
	dmin[1] = a[1]; q.push(1), vis[1] = 1;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		vis[x] = 0;
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i];
			if(dmin[y] > min(dmin[x], a[y]))
			{
				dmin[y] = min(dmin[x], a[y]);
				if(!vis[y]) q.push(y), vis[y] = 1;
			}
		}
	}
	return ;
}
void spfamax()
{
	for (int i = 1; i <= n; ++ i) vis[i] = 0, dmax[i] = 0;
	dmax[n] = a[n], q.push(n), vis[n] = 1;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		vis[x] = 0;
		for (int i = 0; i < f[x].size(); ++ i)
		{
			int y = f[x][i];
			if(dmax[y] < max(dmax[x], a[y]))
			{
				dmax[y] = max(dmax[x], a[y]);
				if(!vis[y]) q.push(y), vis[y] = 1;
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int i = 1; i <= m; ++ i)
	{
		int u, v, c;
		scanf("%d %d %d", &u, &v, &c);
		g[u].push_back(v);
		f[v].push_back(u);
		if(c == 2) g[v].push_back(u), f[u].push_back(v);
	}
	spfamin();
	spfamax();
	for (int i = 1; i <= n; ++ i) ans = max(ans, dmax[i] - dmin[i]);
	printf("%d", ans);
	return 0;
} 

单源最短路的扩展应用

选择最佳线路

看数据范围其实可以暴力跑最短路,但是有一个特点就是终点都是一样的。

可以跑反图,或者直接建立一个虚点。

我发现题目里要到的点字母是s,这是暗示吗
一遍过。

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int w, n, m, s, dis[N], ans;
bool vis[N];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N]; 
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
	dis[s] = 0; q.push((edge){s, 0});
	while(!q.empty())
	{
		int x = q.top().v; q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i].v;
			if(dis[y] > dis[x] + g[x][i].w)
			{
				dis[y] = dis[x] + g[x][i].w;
				q.push((edge){y, dis[y]});
			}
		}
	}
	return ;
}
int main()
{
	while(scanf("%d %d %d", &n, &m, &s) != EOF)
	{
		for (int i = 1; i <= n; ++ i) g[i].clear();
		for (int i = 1; i <= m; ++ i)
		{
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			g[v].push_back((edge){u, w});
		}
		dijkstra();
		scanf("%d", &w);
		ans = INT_MAX;
		for (int i = 1; i <= w; ++ i) 
		{
			int x;
			scanf("%d", &x);
			ans = min(ans, dis[x]);
		}
		if(ans == INT_MAX) ans = -1;
		printf("%d\n", ans);	
	}
	return 0;
}

拯救大兵瑞恩

能用dp转移的状态直接连边。之间的代价就是边权。

#include <bits/stdc++.h>
using namespace std;
const int N = 12;
int n, m, p, s, k;
int rx[5] = {-1, 1, 0, 0};
int ry[5] = {0, 0, -1, 1};
struct edge
{
	int x, y, st, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
priority_queue<edge> q;
vector<edge> g[N][N][1025];
int dis[N][N][1025], mp[N][N][N][N], ky[N][N];
bool vis[N][N][1025];
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) 
	{
		for (int j = 1; j <= m; ++ j)
		{
			for (int st = 0; st < (1 << p); ++ st) dis[i][j][st] = INT_MAX, vis[i][j][st] = 0;
		}
	}
	dis[1][1][0] = 0;
	q.push((edge){1, 1, 0, 0});
	while(!q.empty())
	{
		edge a = q.top(); q.pop();
		if(vis[a.x][a.y][a.st]) continue;
		vis[a.x][a.y][a.st] = 1;
		for (int i = 0; i < g[a.x][a.y][a.st].size(); ++ i)
		{
			edge b = g[a.x][a.y][a.st][i];
			if(dis[b.x][b.y][b.st] > dis[a.x][a.y][a.st] + b.w)
			{
				dis[b.x][b.y][b.st] = dis[a.x][a.y][a.st] + b.w;
				q.push((edge){b.x, b.y, b.st, dis[b.x][b.y][b.st]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d %d", &n, &m, &p);
	scanf("%d", &k);
	for (int i = 1; i <= k; ++ i)
	{
		int x, y, a, b, c;
		scanf("%d %d %d %d %d", &x, &y, &a, &b, &c);
		if(c == 0) mp[x][y][a][b] = -1, mp[a][b][x][y] = -1;
		else mp[x][y][a][b] = c, mp[a][b][x][y] = c;
	}
	scanf("%d", &s);
	for (int i = 1; i<= s; ++ i)
	{
		int x, y, c;
		scanf("%d %d %d", &x, &y, &c);
		ky[x][y] = ky[x][y] | (1 << (c - 1));
	}
	for (int x = 1; x <= n; ++ x)
	{
		for (int y = 1; y <= m; ++ y)
		{
			for (int st = 0; st < (1 << p); ++ st)
			{
				if((st | ky[x][y]) != st) g[x][y][st].push_back((edge){x, y, st | ky[x][y], 0});
				int sst = (st | ky[x][y]);
				for (int i = 0; i < 4; ++ i)
				{
					int nx = x + rx[i], ny = y + ry[i], nst = (sst | ky[nx][ny]);
					if(nx <= 0 || ny <= 0 || nx > n || ny > m) continue;
					if(mp[x][y][nx][ny] == 0)
					{
						g[x][y][sst].push_back((edge){nx, ny, nst, 1});
					}
					else if(mp[x][y][nx][ny] != -1)
					{
						if((sst >> (mp[x][y][nx][ny] - 1)) & 1) 
						{
							g[x][y][sst].push_back((edge){nx, ny, nst, 1});
						}
					}
				}	
			}
		}
	}
	dijkstra();
	int ans = INT_MAX;
	for (int st = 0; st < (1 << p); ++ st) ans = min(ans, dis[n][m][st]);
	if(ans == INT_MAX) ans = -1;
	printf("%d", ans);
	return 0;
}

最短路计数

#include <bits/stdc++.h>
using namespace std;
const int N = 100005, mod = 100003;
int n, dis[N], cnt[N], m;
bool vis[N];
struct edge
{
	int v, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<int> g[N];
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
	q.push((edge){1, 0});
	dis[1] = 0, cnt[1] = 1;
	while(!q.empty())
	{
		int x = q.top().v;
		q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i];
			if(dis[y] == dis[x] + 1) cnt[y] = (cnt[y] + cnt[x]) % mod;
			else if(dis[y] > dis[x] + 1)
			{
				dis[y] = dis[x] + 1;
				cnt[y] = cnt[x];
				q.push((edge){y, dis[y]});
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; ++ i)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dijkstra();
	for (int i = 1; i <= n; ++ i) printf("%d\n", cnt[i]);
	return 0;
}

观光

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, inf = 1000000000;
int n, dis[N][2], cnt[N][2], m, s, e;
bool vis[N][2];
struct edge
{
	int v, t, w;
	bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
	for (int i = 1; i <= n; ++ i) dis[i][0] = dis[i][1] = inf, cnt[i][0] = cnt[i][1] = 0, vis[i][1] = vis[i][0] = 0;
	q.push((edge){s, 0, 0});
	dis[s][0] = 0, cnt[s][0] = 1;
	while(!q.empty())
	{
		int x = q.top().v, t = q.top().t; q.pop();
		if(vis[x][t]) continue;
		vis[x][t] = 1;
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i].v, w = g[x][i].w;
			if(dis[y][0] == dis[x][t] + w) cnt[y][0] += cnt[x][t];
			else if(dis[y][0] > dis[x][t] + w)
			{
				dis[y][1] = dis[y][0], cnt[y][1] = cnt[y][0];
				q.push((edge){y, 1, dis[y][1]});
				dis[y][0] = dis[x][t] + w, cnt[y][0] = cnt[x][t];
				q.push((edge){y, 0, dis[y][0]});
			}
			else if(dis[y][1] == dis[x][t] + w) cnt[y][1] += cnt[x][t];
			else if(dis[y][1] > dis[x][t] + w) 
			{
				dis[y][1] = dis[x][t] + w, cnt[y][1] = cnt[x][t]; 
				q.push((edge){y, 1, dis[y][1]});
			}
		}
	}
	return ;
}
int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d %d", &n, &m);
		for (int i = 1; i <= n; ++ i) g[i].clear();
		for (int i = 1; i <= m; ++ i)
		{
			int x, y, w;
			scanf("%d %d %d", &x, &y, &w);
			g[x].push_back((edge){y, 0, w});
		}
		scanf("%d %d", &s, &e);
		dijkstra();
		if(dis[e][1] == dis[e][0] + 1) printf("%d\n", cnt[e][0] + cnt[e][1]);
		else printf("%d\n", cnt[e][0]);	
	}
	return 0; 
}

2024.10.10

Piggy Back

#include <bits/stdc++.h>
using namespace std;
const int N = 40005, inf = 0x3f3f3f3f;
int B, E, P, n, m, ans = inf;
vector<int> g[N];
int dis[3][N];
void dijkstra(int s, int id)
{
	queue<int> q;
	q.push(s);
	dis[id][s] = 0;
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i];
			if(dis[id][y] != inf) continue;
			dis[id][y] = dis[id][x] + 1;
			q.push(y);
		}
	}
	return ;
}
int main()
{
	scanf("%d %d %d %d %d", &B, &E, &P, &n, &m);
	memset(dis, 0x3f, sizeof(dis));
	for (int i = 1; i <= m; ++ i)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		g[x].push_back(y), g[y].push_back(x);
	}
	dijkstra(1, 1);
	dijkstra(2, 2);
	dijkstra(n, 0);
	for (int i = 1; i <= n; ++ i )
	{
		ans = min(ans, dis[1][i] * B + dis[2][i] * E + dis[0][i] * P); 
	}
	printf("%d", ans);
	return 0;
}

[AGC039B] Graph Partition

#include <bits/stdc++.h>
using namespace std;
const int N = 205, inf = 0x3f3f3f3f;
int n, ans = -1, dis[N];
char mp[N];
vector<int> g[N];
void bfs(int s)
{
	for (int i = 1; i <= n; ++ i) dis[i] = -1;
	dis[s] = 1;
	bool pd = true; int mx = 0;
	queue<int> q;
	q.push(s);
	while(!q.empty())
	{
		int x = q.front();
		mx = max(mx, dis[x]);
		q.pop();
		for (int i = 0; i < g[x].size(); ++ i)
		{
			int y = g[x][i];
			if(dis[y] == -1)
			{
				dis[y] = dis[x] + 1;
				q.push(y);
			}
			else
			{
				if(abs(dis[y] - dis[x]) != 1) pd = false;
			}
			if(!pd) break;
		}
		if(!pd) break;
	}
	if(pd) ans = max(ans, mx);
	return ;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%s", mp + 1);
		for (int j = 1; j <= n; ++ j) 
		{
			if(mp[j] == '1') g[i].push_back(j); 
		}
	}
	for (int i = 1; i <= n; ++ i) bfs(i);
	printf("%d", ans);
	return 0;
}

Sums(同余最短路)

#include <bits/stdc++.h>
using namespace std;
const int N = 500005, inf = 1000000001;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
int n, dis[N], mx = inf, a[N];
bool vis[N];
int read()
{
	int x = 0;char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') 
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x;
}
void dijkstra()
{
	for (int i = 0; i <= mx - 1; ++ i) dis[i] = inf;
	q.push(make_pair(0, 0));
	dis[0] = 0;
	while(!q.empty())
	{
		int x = q.top().second;
		q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for (int i = 1; i <= n; ++ i)
		{
			if(a[i] == mx) continue;
			int y = (x + a[i]) % mx;
			if(dis[y] > (long long)dis[x] + a[i])
			{
				dis[y] = dis[x] + a[i];
				q.push(make_pair(dis[y], y));
			}
		}
	}
	return ;
}
int main()
{
	n = read();
	for (int i = 1; i <= n; ++ i)
	{
		a[i] = read();
		mx = min(mx, a[i]);
	}
	dijkstra();
	int k;
	k = read();
	while(k --)
	{
		int x;
		x = read();
		if(x >= dis[x % mx]) printf("TAK\n");
		else printf("NIE\n"); 
	}
	return 0;
} 
posted @ 2025-02-13 10:38  Helioca  阅读(11)  评论(0)    收藏  举报
Document