【动态规划】【图论最长路】[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的最短路上那么disa(t)+disb(t)=disa(b)那么这个时候发现在A->B和C->D的最短路上最多只有一段路能够重复,如果存在两端那么第一段的结尾到第二段的开始中间的应该是一样的,所以只要处理出所有的A->B且C->D中都经过的路,然后建立新的图,在图中搞拓扑排序,然后处理处最长路就行了(如果有相交那么答案要+1,因为相交存在最优解为1,但是最长路是0)

代码如下:

#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;
}

posted on 2015-10-22 13:24  JeremyGuo  阅读(309)  评论(0编辑  收藏  举报

导航