[CF507E] Breaking Good - 最短路
Description
在一个有 n 个城市 m 条道路的国家,有一个犯罪团伙要去抢劫银行,银行在城市 1,犯罪团伙在城市 n,任务是在城市 1 和城市 n 之间选择一个最短路径,当有多个最短路径的时候选择影响值最小的,为 0 的道路是指未工作的,为 1 的道路是指修好的,在选择好最短路径后,要修复好最短路径上未工作的路,破坏其他路径上工作的路径
Solution
梳理一下题意,影响 = 修复 + 破坏 = 最短路长 - 最短路上工作路数 + 工作总道路数 - 最短路上工作路数 = 最短路长 + 工作总道路数 - 2 最短路上工作道路数
要最小化影响值,首先要求最短路,然后要选择最短路上工作道路数最多的
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
struct num
{
int dist;
int sum;
num(int dist = 1e18, int sum = 0) : dist(dist), sum(sum)
{
}
num operator+(const num &rhs) const
{
return num(dist + rhs.dist, sum + rhs.sum);
}
bool operator<(const num &rhs) const
{
if (dist == rhs.dist)
return sum > rhs.sum;
return dist < rhs.dist;
}
};
int n, m;
vector<pair<int, int>> g[N];
num f[N];
int v[N], from[N][3];
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
vector<tuple<int, int, int>> src;
for (int i = 1; i <= m; i++)
{
int t1, t2, t3;
cin >> t1 >> t2 >> t3;
src.push_back(make_tuple(t1, t2, t3));
g[t1].push_back({t2, t3});
g[t2].push_back({t1, t3});
}
queue<int> que;
que.push(1);
f[1] = num(0, 0);
v[1] = 1;
while (que.size())
{
auto p = que.front();
que.pop();
for (auto [q, w] : g[p])
{
if (f[p] + num(1, w) < f[q])
{
f[q] = f[p] + num(1, w);
from[q][0] = p;
from[q][1] = q;
from[q][2] = w;
if (v[q] == 0)
{
que.push(q);
v[q] = 1;
}
}
}
}
map<pair<int, int>, int> mp;
vector<tuple<int, int, int>> ans;
int p = n;
while (p > 1)
{
mp[{from[p][0], from[p][1]}] = mp[{from[p][1], from[p][0]}] = 1;
p = from[p][0];
}
for (auto [x, y, z] : src)
{
if (mp[{x, y}])
{
if (z == 0)
ans.push_back(make_tuple(x, y, z ^ 1));
}
else
{
if (z == 1)
ans.push_back(make_tuple(x, y, z ^ 1));
}
}
cout << ans.size() << endl;
if (ans.size() == 0)
return 0;
for (int i = ans.size() - 1; i >= 0; i--)
{
auto [x, y, z] = ans[i];
cout << x << " " << y << " " << z << endl;
}
}