【动态规划】【图论最长路】[NOIP模拟赛]益智游戏
题目描述
小P 和小R 在玩一款益智游戏。游戏在一个正权有向图上进行。 小P 控制的角色要从A 点走最短路到B 点,小R 控制的角色要从C 点走最短路到D 点。 一个玩家每回合可以有两种选择,移动到一个相邻节点或者休息一回合。 假如在某一时刻,小P 和小R 在相同的节点上,那么可以得到一次特殊奖励,但是在每 个节点上最多只能得到一次。 求最多能获得多少次特殊奖励
输入
5 5
1 2 1
2 3 2
3 4 4
5 2 3
5 3 5
1 3 5 4
输出
2
首先可以预处理A,B,C,D分别为原点的最短路,然后可以发现如果一个点t在A->B的最短路上那么
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 50000;
const int MAXM = 200000;
typedef long long LL;
const LL INF = 0x7f7f7f7f7f7f7f7fLL;
struct node{
LL w;
int v;
node *next;
}Edges[MAXM+10], Edges2[MAXM+10], *ecnt=Edges, *adj[2][MAXN+10], *ecnt2=Edges2;
node Edges3[MAXM+10], *adj3[MAXN+10], *e3=Edges3;
int ct[MAXN+10];
void adde(int u, int v){
++e3;
e3->v = v;
e3->next = adj3[u];
adj3[u] = e3;
}
int n, m, a, b, c, d;
LL di[4][MAXN+10];
int dp[MAXN+10];
bool vis[MAXN+10];
int Max(){
queue<int> que;
for(int i=1;i<=n;i++) if(!ct[i]) que.push(i);
int ret = 0;
while(!que.empty()){
int u = que.front(); que.pop();
for(node *p=adj3[u];p;p=p->next){
dp[p->v] = max(dp[p->v], dp[u]+1);
ret = max(ret, dp[p->v]);
ct[p->v] -- ;
if(!ct[p->v]) que.push(p->v);
}
}
return ret;
}
void addedge(int u, int v, LL w){
++ecnt;
ecnt->v = v;
ecnt->w = w;
ecnt->next = adj[0][u];
adj[0][u] = ecnt;
++ecnt2;
ecnt2->v = u;
ecnt2->w = w;
ecnt2->next = adj[1][v];
adj[1][v] = ecnt2;
}
void dij(int s, LL *dis, int f){
for(int i=1;i<=n;i++) dis[i] = INF;
dis[s] = 0;
memset(vis, 0, sizeof vis);
priority_queue<pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > que;
que.push(make_pair(dis[s], s));
vis[s] = true;
while(!que.empty()){
pair<int, int> u = que.top(); que.pop();
vis[u.second] = true;
for(node *p=adj[f][u.second];p;p=p->next){
if(!vis[p->v] && dis[p->v] > dis[u.second] + p->w){
dis[p->v] = dis[u.second] + p->w;
que.push(make_pair(dis[p->v], p->v));
}
}
}
}
int main(){
int u, v;
LL w;
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++){
scanf("%d%d", &u, &v);
cin>>w;
addedge(u, v, w);
}
scanf("%d%d%d%d", &a, &b, &c, &d);
dij(a, di[0], 0); dij(b, di[1], 1);
dij(c, di[2], 0); dij(d, di[3], 1);
if(di[0][b] == INF || di[2][d] == INF){
printf("-1\n");
return 0;
}
bool have = false;
for(int i=1;i<=n;i++)
if(di[0][i] + di[1][i] == di[0][b] && di[2][i] + di[3][i] == di[2][d]){
have = true;
break;
}
for(int i=1;i<=n;i++){
for(node *p=adj[0][i];p;p=p->next){
v = p->v;
if(di[0][i]+p->w+di[1][v]==di[0][b] && di[2][i]+p->w+di[3][v]==di[2][d]){
ct[v]++;
adde(i, v);
}
}
}
printf("%d\n", Max() + int(have));
return 0;
}