P2648 赚钱
思路:
题目名字很好啊,赚钱赚钱赚钱 ,咳咳,回来回来。首先啊我们的主人公非常的牛X啊,这个啊他可以在每个城市挣到钱,而且呢挣完了就可以跑路😂。
那么说,我们可以将每条初始的路的权值都看做 d d d,将可以进行飞行的路呢看做负值,首先我们要考虑这个什么时候输出 o r z orz orz啊,那么这时候如果形成正环,我们这个挣的钱呢那肯定是停不下来。那这个时候他肯定是要输出 o r z orz orz的。
那么除此之外,我们要考虑如何遍历这张图,首先我们可以用一个超级源点,这个操作非常的经典啊,大家记好笔记,也就是说,我们要在已有点之外建立一个点,一般为 0 0 0,随后,从建立该点指向各个起点的单向边,该边的权值均为0,这样就能保证我们所求的最短路均是最短,而且不会形成环破坏图。然后我们以这个超级源点为起点,跑一遍spfa即可,最后在所有的答案中取最大值。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
typedef pair<int, int> pii;
const int N = 4e5 + 10;
int e[N], ne[N], h[N], idx,w[N];;
void add(int x, int y, int z=0) {
e[idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx++;
}
int dis[N];
bool st[N];
int cnt[N];
int d, p, c, f;
void spfa() {
memset(dis, -0x3f, sizeof dis);
memset(st, false, sizeof st);
memset(cnt, 0, sizeof cnt);
queue<int>q;
dis[0] = 0;
q.push(0);
st[0] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dis[j] < dis[t] - w[i] + d) {
dis[j] = dis[t] - w[i] + d;
if (cnt[j] > c) {
puts("orz");
return;
}
if (!st[j]) {
cnt[j]++;
st[j] = true;
q.push(j);
}
}
}
}
int ans = -1;
for (int i = 1; i <= c; i++) {
ans = max(ans, dis[i]);
}
cout << ans<< endl;
}
int main() {
memset(h, -1, sizeof h);
cin >> d >> p >> c >> f;
for (int i = 1; i <= p; i++) {
int x, y;
cin >> x >> y;
add(x, y);
}
for (int i = 1; i <= f; i++) {
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
}
for (int i = 1; i <= c; i++)add(0, i);
spfa();
}
当然,如果我们没有想到超级源点,我们亦可以对每个点跑一遍spfa,还好这个题数据水,也可以过。但是遇到这种既需要求对多个起点的最短路时,使用floyd会超时,对每个起点都跑一次最短路也会超时时,就要考虑超级源点了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
typedef pair<int, int> pii;
const int N = 4e5 + 10;
int e[N], ne[N], h[N], idx,w[N];;
void add(int x, int y, int z=0) {
e[idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx++;
}
int dis[N];
bool st[N];
int cnt[N];
int d, p, c, f;
bool spfa(int hh) {
memset(dis, -0x3f, sizeof dis);
memset(st, false, sizeof st);
memset(cnt, 0, sizeof cnt);
queue<int>q;
dis[hh] = d;
q.push(hh);
st[hh] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dis[j] < dis[t] - w[i] + d) {
dis[j] = dis[t] - w[i] + d;
cnt[j]++;
if (cnt[j] >= c)return true;
if (!st[j]) {
st[j] = true;
q.push(j);
}
}
}
}
return false;
}
int main() {
memset(h, -1, sizeof h);
cin >> d >> p >> c >> f;
for (int i = 1; i <= p; i++) {
int x, y;
cin >> x >> y;
add(x, y);
}
for (int i = 1; i <= f; i++) {
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
}
int ans = -1, flag = 0;;
for (int i = 1; i <= c; i++)
{
if (spfa(i)) {
puts("orz");
flag = 1;
break;
}
for (int j = 1; j <= c; j++)ans = max(ans, dis[j]);
}
if (!flag)
{
cout << ans << endl;
}
}