BZOJ1922 SDOI2010 大陆争霸 最短路

题意:给定一个图,图中有保护关系(u,v)表示到v之前必须先到一次u,求从1到N的最短路

题解:

定义d1[i]为直接到达i的最短距离,这个的更新和普通的Dijkstra一样

定义d2[i]为解除i的所有保护的最短距离(不一定要在i结束),这个更新起来很简单,每经过一个节点就将其所控制的城市的发生器数全部--,没有发生器的城市直接用当前的距离更新即可。

最后答案显然就是max(d1[N],d2[N])

#include <queue>
#include <vector>
#include <functional>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=3000+2;
const int MAXM=70000+2;
struct HASH{
    int u,w;
    HASH *next;
    HASH(){}
    HASH(int _u,int _w,HASH *_next):u(_u),w(_w),next(_next){}
}*table[MAXN],mem[2*MAXM];
struct NODE{
    int u,w;
    NODE(){}
    NODE(int _u,int _w):u(_u),w(_w){};
    friend bool operator<(NODE a,NODE b){ return a.w>b.w;}
};
int N,M,t[MAXN],d1[MAXN],d2[MAXN],cnt;
bool flag[MAXN];
vector<int> pro[MAXN];
priority_queue<NODE> q;

void Insert(int u,int v,int w){ table[u]=&(mem[cnt++]=HASH(v,w,table[u]));}

int Dijkstra(int s,int e){
    memset(d1,0X7F,sizeof(d1));
    d1[s]=0,q.push(NODE(s,0));

    int x;
    while(!q.empty()){
        x=q.top().u,q.pop();

        if(flag[x]) continue;
        flag[x]=1;

        int dist=max(d1[x],d2[x]);
        for(HASH *p=table[x];p;p=p->next)
            if(d1[p->u]>dist+p->w){
                d1[p->u]=dist+p->w;
                if(!t[p->u]) q.push(NODE(p->u,max(d1[p->u],d2[p->u])));
            }

        for(int i=0;i<pro[x].size();i++){
            t[pro[x][i]]--;
            d2[pro[x][i]]=max(d2[pro[x][i]],dist);
            if(!t[pro[x][i]]) q.push(NODE(pro[x][i],max(d1[pro[x][i]],d2[pro[x][i]])));
        }
    }

    return max(d1[e],d2[e]);
}

int main(){
    cin >> N >> M;
    for(int i=1,u,v,w;i<=M;i++){
        cin >> u >> v >> w;
        Insert(u,v,w);
    }
    for(int i=1;i<=N;i++){
        cin >> t[i];
        for(int j=1,k;j<=t[i];j++){
            cin >> k;
            pro[k].push_back(i);
        }
    }

    cout << Dijkstra(1,N) << endl;

    return 0;
}
View Code

 

posted @ 2017-02-27 22:50  WDZRMPCBIT  阅读(148)  评论(0编辑  收藏  举报