标签:最大的 邻接表 return ++ time 练习 数据 vector front
题意:在一个无向图中,求点 n 到点 1 的最短路径。
??用邻接表 dijkstra 即可不需要考虑重边。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef pair<int, int> P;
typedef long long ll;
const int INF = 2e9, N = 1005, M = 4005;
int t, n, tot;
int ver[M], edge[M], Next[M], head[N], d[N], v[N];
priority_queue<P, vector<P>, greater<P> > q;
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}
void dijkstra() {
memset(d, 0x3f, sizeof(d));
memset(v, 0, sizeof(v));
d[n] = 0;
q.push(P(0, n));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z) {
d[y] = d[x] + z;
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d%d", &t, &n);
int x, y, z;
while (t--) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dijkstra();
printf("%d\n", d[1]);
return 0;
}
题意:湖中有 n 块石头,两只青蛙。在1号石头的 Freddy 蛙想去找在 2 号石头的 Fiona 蛙。青蛙距离指所有可能跳跃路径中在两块石头间跳跃距离最远的距离。求 1 号石头到 2 号石头所有可能路径中最小的青蛙距离。
??可以 dijkstra,改变一下松弛方程即可,不知道为啥 G++ 要改成 float 才能过。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 2e9, N = 205;
struct Point {
double x, y;
}p[N];
int n;
double d[N], mp[N][N];
int v[N];
priority_queue<P, vector<P>, greater<P> > q;
double dis(Point a, Point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void dijkstra(int s) {
for (int i = 1; i <= n; ++i) d[i] = INF;
memset(v, 0, sizeof(v));
d[s] = 0;
q.push(P(0, s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = 1; i <= n; ++i) {
if (d[i] > max(d[x], mp[i][x])) {
d[i] = max(d[x], mp[i][x]);
q.push(P(d[i], i));
}
}
}
}
int main()
{
int cnt = 0;
while (scanf("%d", &n), n) {
for (int i = 1; i <= n; ++i) {
scanf("%lf%lf", &p[i].x, &p[i].y);
}
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
mp[i][j] = mp[j][i] = dis(p[i], p[j]);
}
}
dijkstra(1);
printf("Scenario #%d\n", ++cnt);
printf("Frog Distance = %.3lf\n\n", d[2]);
}
return 0;
}
题意:n 个点的无向图中,求 1 到 n 的所有路径中边最小值中最大的。
??dijkstra + minmax,优先队列记得换成大根堆,否则会 T。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 2e9, N = 1005, M = 1e6 + 5;
int t, n, m, tot;
int v[N], d[N];
int head[N], ver[M], edge[M], Next[M];
priority_queue<P, vector<P>, less<P> > q; // 大根堆
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}
void dijkstra(int s) {
memset(v, 0, sizeof(v));
q.push(P(INF, s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (d[y] < min(d[x], edge[i])) {
d[y] = min(d[x], edge[i]);
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d", &t);
for (int i = 1; i <= t; ++i) {
memset(head, 0, sizeof(head));
memset(d, 0, sizeof(d));
d[1] = INF;
tot = 0;
scanf("%d%d", &n, &m);
for (int j = 1; j <= m; ++j) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dijkstra(1);
printf("Scenario #%d:\n%d\n\n", i, d[n]);
}
return 0;
}
题意:n 个点 m 条边的有向图,奶牛从 a 到花费 t 时间,所有奶牛到奶牛 x 去参加聚会,聚会完后回到农场,求所有奶牛参加聚会并回来的最短时间的最大值。
??先求x到各个农场的最小时间,再反向建图求x到各个农场的最小时间,二者之和的最大值即为答案。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 2e9, N = 1005, M = 1e5 + 5;
struct edge {
int to, nxt, cost;
edge() {}
edge(int to, int nxt, int cost) : to(to), nxt(nxt), cost(cost) {}
}g[M], invg[M];
int n, m, x, tot;
int head[N], invhead[N], dis[N], invdis[N];
void add(int a, int b, int c) {
g[++tot] = edge(b, head[a], c);
head[a] = tot;
invg[tot] = edge(a, invhead[b], c);
invhead[b] = tot;
}
void dijkstra(edge (&G)[M], int (&d)[N], int (&h)[N]) {
priority_queue<P, vector<P>, greater<P> > q;
memset(d, 0x3f, sizeof(d));
d[x] = 0;
q.push(P(0, x));
while (!q.empty()) {
int x = q.top().second;
q.pop();
for (int i = h[x]; i; i = G[i].nxt) {
int y = G[i].to;
if (d[y] > d[x] + G[i].cost) {
d[y] = d[x] + G[i].cost;
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &x);
int a, b, c;
while (m--) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
dijkstra(g, dis, head);
dijkstra(invg, invdis, invhead);
int ans = 0;
for (int i = 1; i <= n; ++i) {
ans = max(ans, dis[i] + invdis[i]);
}
printf("%d\n", ans);
return 0;
}
题意:N 种货币,M 个交换点,每个交换点只能交换 2 种货币,交换公式为 (now - c) * r,其中 c(\(0\le c\le10^2\))为税款,r(\(10^{-2}\le r\le10^2\))为汇率,Nick 有第 S 种货币,V 本金,问能否经过若干次交换后使价值增加。
??spfa判断负环即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 2e9, N = 105, M = 205;
int n, m, s, tot;
double v;
int head[N], vis[N], cnt[N];
int ver[M], nxt[M];
double d[N], co[M], rate[M];
void add(int x, int y, double r, double c) {
ver[++tot] = y, co[tot] = c, rate[tot] = r, nxt[tot] = head[x], head[x] = tot;
}
void spfa() {
queue<int> q;
vis[s] = 1;
cnt[s] = 1;
d[s] = v;
q.push(s);
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] < (d[x] - co[i]) * rate[i]) {
d[y] = (d[x] - co[i]) * rate[i];
if (!vis[y]) {
q.push(y);
vis[y] = 1;
if(++cnt[y] == n) {
puts("YES");
return;
}
}
}
}
}
puts("NO");
}
int main()
{
scanf("%d%d%d%lf", &n, &m, &s, &v);
int x, y;
double r1, c1, r2, c2;
while (m--) {
scanf("%d%d%lf%lf%lf%lf", &x, &y, &r1, &c1, &r2, &c2);
add(x, y, r1, c1);
add(y, x, r2, c2);
}
spfa();
return 0;
}
题意:F 个农场,N 块田地,M 个双向路径,W 个虫洞(单向路径),虫洞是时光倒流路径,农夫 Jorn 想知道能否遇到以前的自己。
??下面默认 1 为源点,用 spfa 判负环。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 2e9;
const int N = 505, M = 5205;
int t, n, m, w, tot;
int d[N], v[N], cnt[N];
int head[N], ver[M], edge[M], nxt[M];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void spfa() {
queue<int> q;
memset(d, 0x3f, sizeof(d));
memset(v, 0, sizeof(v));
memset(cnt, 0, sizeof(cnt));
d[1] = 0;
cnt[1] = 1;
v[1] = 1;
q.push(1);
while (!q.empty()) {
int x = q.front();
q.pop();
v[x] = 0;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
if (!v[y]) {
q.push(y);
v[y] = 1;
if (++cnt[y] == n) {
puts("YES");
return;
}
}
}
}
}
puts("NO");
}
int main()
{
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &n, &m, &w);
int x, y, z;
tot = 0;
memset(head, 0, sizeof(head));
while (m--) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
while (w--) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, -z);
}
spfa();
}
return 0;
}
??若测试数据有非连通图,我们用 floyd 判断负权勉强可以过。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 2e9, N = 505;
int t, n, m, w;
int d[N][N];
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (d[i][j] > d[i][k] + d[k][j])
d[i][j] = d[i][k] + d[k][j]; // 用min会T
}
if (d[i][i] < 0) {
puts("YES");
return;
}
}
}
puts("NO");
}
int main()
{
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &n, &m, &w);
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; ++i) d[i][i] = 0;
int x, y, z;
while (m--) {
scanf("%d%d%d", &x, &y, &z);
if (z < d[x][y])
d[x][y] = d[y][x] = z;
}
while (w--) {
scanf("%d%d%d", &x, &y, &z);
d[x][y] = -z;
}
floyd();
}
return 0;
}
题意:n 个处理器,第一个处理器给另一个处理器发送信息后,两个处理器可以同时给其他连接的处理器发送信息,但信息不一定同时到达,给出\(n\times n\)的邻接矩阵,A(i,j)表示处理器i到j的通信时间,网络是无向的即 A(i,j)=A(j,i),处理器发送信息到自身不需要网络通信即 A(i,i)=0,因此只给出下三角矩阵,求第一个处理器广播信息到其他所有处理器的最短时间。
??dijkstra裸题,神奇的POJ用stoi会CE。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <string>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 2e9, N = 105;
int n;
int mp[N][N], d[N], v[N];
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
memset(d, 0x3f, sizeof(d));
d[1] = 0;
q.push(P(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = 1;
for (int y = 1; y <= n; ++y) {
if (d[y] > d[x] + mp[x][y]) {
d[y] = d[x] + mp[x][y];
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d", &n);
string s;
memset(mp, 0x3f, sizeof(mp));
for (int i = 2; i <= n; ++i) {
for (int j = 1; j < i; ++j) {
cin >> s;
if (s != "x") mp[i][j] = mp[j][i] = atoi(s.c_str());
}
}
dijkstra();
int ans = 0;
for (int i = 2; i <= n; ++i)
ans = max(ans, d[i]);
printf("%d\n", ans);
return 0;
}
题意:n 头牛程序竞赛,如果 A 拥有比 B 更高的技术水平,那么 A 将永远打败 B,给定 M 场比赛的结果,问有多少牛排名可以确定。
??用floyd传递闭包,若一个牛和其余牛关系确定,则该牛排名确定。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 2e9, N = 105;
int n, m;
int win[N][N];
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j= 1; j <= n; ++j) {
win[i][j] |= win[i][k] & win[k][j];
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
while (m--) {
int a, b;
scanf("%d%d", &a, &b);
win[a][b] = 1;
}
floyd();
int ans = 0;
for (int i = 1; i <= n; ++i) {
int flag = 0;
for (int j = 1; j <= n; ++j) {
if (i == j) continue;
if (!win[i][j] && !win[j][i]) {
flag = 1;
break;
}
}
if (!flag) ans++;
}
printf("%d\n", ans);
return 0;
}
题意:给定 n 种货币,m 种货币汇率,问是否存在一种套利方式,使 1 单位的货币变成比 1 单位更多的同种货币。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <string>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 2e9, N = 35;
const double eps = 1e-8;
int n, m;
map<string, int> mp;
double d[N][N];
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
d[i][j] = max(d[i][j], d[i][k] * d[k][j]);
}
if (d[i][i] - 1 > eps) {
puts("Yes");
return;
}
}
}
puts("No");
}
int main()
{
int cnt = 0;
while (scanf("%d", &n), n) {
mp.clear();
string s;
for (int i = 1; i <= n; ++i) {
cin >> s;
mp[s] = i;
d[i][i] = 1;
}
scanf("%d", &m);
string cur1, cur2;
double rate;
for (int i = 1; i <= m; ++i) {
cin >> cur1 >> rate >> cur2;
d[mp[cur1]][mp[cur2]] = rate;
}
printf("Case %d: ", ++cnt);
floyd();
}
return 0;
}
题意:给定 n 个点和 m 个单向路径,求 1 号点到其他点的最短路及其他点到 1 号点的最短路之和。
??dijkstra(2219ms),可以用快读加下速。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<ll, int> P;
const ll INF = 1e18;
const int N = 1e6 + 5, M = 2e6 + 5;
int t, n, m, tot;
ll dis[N], rdis[N];
int head[N], rhead[N];
int ver[M], edge[M], nxt[M], vis[N];
void add(int (&h)[N], int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = h[x], h[x] = tot;
}
void dijkstra(ll (&d)[N], int (&h)[N]) {
priority_queue<P, vector<P>, greater<P> > q;
for (int i = 1; i <= n; ++i) d[i] = INF;
memset(vis, 0, sizeof(vis));
d[1] = 0;
q.push(P(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = h[x]; i; i = nxt[i]) {
int y = ver[i];
ll z = d[x] + (ll)edge[i];
if (d[y] > z) {
d[y] = z;
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
memset(head, 0, sizeof(head));
memset(rhead, 0, sizeof(rhead));
int x, y, z;
tot = 0;
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &x, &y, &z);
add(head, x, y, z);
add(rhead, y, x, z);
}
dijkstra(dis, head);
dijkstra(rdis, rhead);
ll ans = 0;
for (int i = 1; i <= n; ++i) ans += dis[i] + rdis[i];
printf("%lld\n", ans);
}
return 0;
}
题意:n 个人分糖果,m 个约束条件\((a,b,c)\)表示b的糖果不能比 a 多 c 个以上,即\(d[a]+c\ge d[b]\),求 1 比 n 少的最大糖果差异数。
??差分约束系统问题,图中有负边则必须使用 Bellman-Ford 算法,\(d[a]+c\ge d[b]\),可以视为从 a 到 b 连一条长度为 c 的有向边,转化为求 1 到 n 的最短路。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 2e9, N = 3e4 + 5, M = 15e4+5;
int n, m, tot;
int d[N], head[N], vis[N];
int ver[M], edge[M], nxt[M];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
memset(d, 0x3f, sizeof(d));
d[1] = 0;
q.push(P(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
int x, y, z;
while (m--) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
dijkstra();
printf("%d\n", d[n]);
return 0;
}
题意:从家去学校,步行速度\(10km/h\),地铁速度\(40km/h\),给定家和学校的坐标,以及若干条地铁线路地铁站坐标,求家到学校的最少时间。
??根据题意见图跑最短路即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<double, int> P;
const int N = 205, M = 1e5 + 5;
const double INF = 1e18;
struct point {
int x, y;
point() {}
point(int x, int y) : x(x), y (y) {}
}p[N];
int cnt, tot;
double d[N], edge[M];
int vis[N], head[N];
int ver[M], nxt[M];
double getdis(point a, point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void add(int x, int y, double z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
for (int i = 1; i <= cnt; ++i) d[i] = INF;
d[1] = 0;
q.push(P(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
q.push(P(d[y], y));
}
}
}
}
int main()
{
int sx, sy, ex, ey;
scanf("%d%d%d%d", &sx, &sy, &ex, &ey);
p[++cnt] = point(sx, sy);
int x, y;
while (~scanf("%d%d", &x, &y)) {
p[++cnt] = point(x, y);
while (scanf("%d%d", &x, &y), x + 1) {
p[++cnt] = point(x, y);
double dis = getdis(p[cnt-1], p[cnt]) * 60.0 / 40000;
add(cnt - 1, cnt, dis);
add(cnt, cnt - 1, dis);
}
}
p[++cnt] = point(ex, ey);
for (int i = 1; i < cnt; ++i) {
for (int j = i + 1; j <= cnt; ++j) {
double dis = getdis(p[i], p[j]) * 60.0 / 10000;
add(i, j, dis);
add(j, i, dis);
}
}
dijkstra();
printf("%d\n", int(d[cnt] + 0.5));
return 0;
}
题意:N 件物品,每件物品价格 P,主人地位等级 L,替代品总数X,两人地位等级差超过 M 不能间接交易,求 1 号物品的最少价格。
??以 0 为源点,物品所需的金币数为权值见图,问题即求 d[1],酋长等级 l[1],枚举以\(l[1]-m\to l[1]\)为最小等级长度为 m 的区间求最短路即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int ,int> P;
const int INF = 2e9, N = 105, M = 1e4 + 5;
int m, n, p, x, tot, level;
int d[N], head[N], l[N], vis[N];
int ver[M], edge[M], nxt[M];
void add(int u, int v, int w) {
ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
}
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
d[0] = 0;
q.push(P(0 ,0));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i];
if (l[v] < level || l[v] > level + m) continue;
if (d[v] > d[u] + edge[i]) {
d[v] = d[u] + edge[i];
q.push(P(d[v], v));
}
}
}
}
int main()
{
scanf("%d%d", &m, &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d", &p, &l[i], &x);
add(0, i, p);
int u, v;
while (x--) {
scanf("%d%d", &u, &v);
add(u, i, v);
}
}
int ans = INF;
for (level = l[1] - m; level <= l[1]; ++level) {
dijkstra();
ans = min(ans, d[1]);
}
printf("%d\n", ans);
return 0;
}
题意:n 个路口,每个路口通向多条路,默认向第 1 条路口,轨道通向其他路口需要转换一次开关,求路口 A 到路口 B 所需的最小转换次数。
??通向默认路口权值为 0,转换一次开关为 1 建图。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 105;
int n, a, b, t, y;
int g[N][N];
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
}
}
}
int main()
{
memset(g, 0x3f, sizeof(g));
scanf("%d%d%d", &n, &a, &b);
for (int x = 1; x <= n; ++x) {
scanf("%d", &t);
for (int j = 1; j <= t; ++j) {
scanf("%d", &y);
if (j == 1) g[x][y] = 0;
else g[x][y] = 1;
}
}
floyd();
if (g[a][b] == INF) puts("-1");
else printf("%d\n", g[a][b]);
return 0;
}
题意:n 个交叉路口,每个路口有拥挤度\(a_i\),旅行者从路口 i 到 j 城市管理者获得\((a_j-a_i)^3\)的费用,求 0 号路口到其他路口的最少费用。
??可能存在负环,用 spfa 求最短路并标记负环上的每一个点。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 205, M = 2e4 + 5;
int t, n, m, q, tot;
int a[N], vis[N], d[N], cnt[N], head[N], cir[N];
int ver[M], edge[M], nxt[M];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void dfs(int x) {
cir[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (!cir[x]) dfs(y);
}
}
void spfa() {
queue<int> q;
memset(vis, 0, sizeof(vis));
memset(d, 0x3f, sizeof(d));
memset(cnt, 0, sizeof(cnt));
memset(cir, 0, sizeof(cir));
d[1] = 0;
vis[1] = 1;
cnt[1] = 1;
q.push(1);
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (cir[y]) continue;
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
if (!vis[y]) {
vis[y] = 1;
q.push(y);
if (++cnt[y] >= n) dfs(y);
}
}
}
}
}
int main()
{
scanf("%d", &t);
for (int i = 1; i <= t; ++i) {
memset(head, 0, sizeof(head));
scanf("%d", &n);
for (int j = 1; j <= n; ++j) scanf("%d", &a[j]);
scanf("%d", &m);
int x, y;
tot = 0;
while (m--) {
scanf("%d%d", &x, &y);
add(x, y, (a[y] - a[x]) * (a[y] - a[x]) * (a[y] - a[x]));
}
spfa();
printf("Case %d:\n", i);
scanf("%d", &q);
while (q--) {
scanf("%d", &x);
if (cir[x] || d[x] < 3 || d[x] == INF) puts("?");
else printf("%d\n", d[x]);
}
}
return 0;
}
题意:n 个点,每个点都属于一个层 l,相邻两层距离为 c,另外给出 m 条无向边,求点 1 到点 n 的最短路。
??利用拆点的思想,相邻两层所有点连边复杂度高,将每一层视为一个点,由于同层的点不一定连通,每层拆为入点出点两个点,不妨设\(n+1\sim3n\)中奇数号为出点偶数号为入点,每层内的点连分别连至出入点,相邻两层出入点相连接。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f, N = 3e5 + 5, M = 6e5 + 5;
int t, n, m, c, tot;
int d[N], vis[N], head[N];
int ver[M], edge[M], nxt[M];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
memset(vis, 0, sizeof(vis));
memset(d, 0x3f, sizeof(d));
d[1] = 0;
q.push(P(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
q.push(P(d[y], y));
}
}
}
}
int main()
{
scanf("%d", &t);
for (int i = 1; i <= t; ++i) {
memset(head, 0, sizeof(head));
tot = 0;
scanf("%d%d%d", &n, &m, &c);
int x, y, z;
for (int j = 1; j <= n; ++j) {
scanf("%d", &x);
add(j, n + 2 * x - 1, 0);
add(n + 2 * x, j, 0);
}
for (int j = 1; j <= n; ++j) {
add(n + 2 * j - 1, n + 2 * (j + 1), c);
add(n + 2 * j + 1, n + 2 * j, c);
}
for (int j = 1; j <= m; ++j) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dijkstra();
printf("Case #%d: ", i);
if (d[n] == INF) puts("-1");
else printf("%d\n", d[n]);
}
return 0;
}
题意:。
题意:给出一个\(n\times n\)的矩阵\(c_{i,j}\),找出一个\(n\times n\)的 0-1 矩阵\(x_{i,j}\)满足
使得\(\displaystyle\sum c_{i,j}*x_{i,j}(1\le i,j\le n)\)最小,求这个最小值。
??条件 1:1 号结点出度为 1,且不指向自身;条件 2:n 号结点入度为 1,发出者不是自身;条件 3:\(2\sim n-1\)的每个结点出度等于入度。原问题可以转化为两种情况,1. 结点 1 最终指向 n,求从 1 号结点到 n 号结点的最短路 d[n]。2. 结点 1 形成自环,则结点 n 也必然形成自环,求 d[1] + d[n],d[1] 以 1 为起点,d[n] 以 n 为起点。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 305;
int n;
int d[N], vis[N], c[N][N];
void spfa(int s) {
queue<int> q;
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i) {
if (i == s) continue;
d[i] = c[s][i];
q.push(i);
vis[i] = 1;
}
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = 1; i <= n; ++i) {
if (d[i] > d[x] + c[x][i]) {
d[i] = d[x] + c[x][i];
if (!vis[i]) q.push(i), vis[i] = 1;
}
}
}
}
int main()
{
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%d", &c[i][j]);
}
}
spfa(1);
int ans = d[n];
int d1 = d[1];
spfa(n);
int d2 = d[n];
printf("%d\n", min(ans, d1 + d2));
}
return 0;
}
题意:n 头奶牛在一条直线上按编号排列,ml 对奶牛关系好,进食的距离不能超过某值,md 对奶牛关系不好,进食的距离不能小于某值,满足条件的排列中,求 1 号牛和 n 号牛的最大距离,若没有的排列输出 -1,1 号和 n 号距离无穷大输出 -2。
??一道差分约束系统问题,i 号牛位置为\(d[i]\),\(d[i]\)单调递增,对关系好的\((x,y,z)\),\(d[y]\le d[x]+z\),视为从 x 到 y 连一条长度为 z 的有向边;对关系不好的\((x,y,z)\),\(d[x]+z\le d[y]\),视为从 y 到 x 连一条长度 -z 的有向边,\(d[n]-d[1]\)的最大值即 1 到 n 的最短路。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1005, M = 2e4 + 5;
int n, ml, md, tot;
int d[N], vis[N], head[N], cnt[N];
int ver[M], edge[M], nxt[M];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void spfa() {
queue<int> q;
memset(d, 0x3f, sizeof(d));
d[1] = 0;
vis[1] = 1;
q.push(1);
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (d[y] > d[x] + edge[i]) {
d[y] = d[x] + edge[i];
if (!vis[y]) {
vis[y] = 1;
q.push(y);
if (++cnt[y] >= n) {
puts("-1");
return;
}
}
}
}
}
if (d[n] == INF) puts("-2");
else printf("%d\n", d[n]);
}
int main()
{
scanf("%d%d%d", &n, &ml, &md);
int x, y, z;
while (ml--) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
while (md--) {
scanf("%d%d%d", &x, &y, &z);
add(y, x, -z);
}
spfa();
return 0;
}
标签:最大的 邻接表 return ++ time 练习 数据 vector front
原文地址:https://www.cnblogs.com/2inf/p/13586013.html