题意 :
给出N个点,求1号点到N号点的最短路,每个点有一定数量的保护它的点,需要先遍历所有保护它的点才能经过。
本来想用spfa来着,结果发现死活只有10分……换成dijkstra立马就A了QAQ。
改动下最短路的松弛操作,每次只更新没有被保护节点,到达这个节点后如果有其他城市可以被更新(不再被保护),更新它的dist 为max(dis,dist)。记录dis[i]和dist[i]分别表示 i 城市的可进入时间和到达时间,用num[i]记录一个城市剩余的结界保护数量,每次从堆中取出f,更新 f 所连通节点的dist和 f 所保护节点的 dis ,f 所保护节点的num –,如num为 0 ,就把节点入堆。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
const int size = 200100;
int head[size],next[size],dist[size],dis[size];
int map[3010][3010];
int num[3010];
int nu[3010];
bool use[size];
struct dc
{
int t,d;
}l[size];
int tot = 1;
void build(int f,int t,int d)
{
l[tot].t = t;
l[tot].d = d;
next[tot] = head[f];
head[f] = tot ++;
}
bool pd(int t)
{
if(num[t] == 0)
return true;
return false;
}
priority_queue<pair < int , int > , vector< pair < int , int > > , greater< pair< int , int > > >q;
void dijkstra()
{
memset(dist,127/3,sizeof(dist));
q.push(make_pair(0,1));
dist[1] = 0;
while(!q.empty())
{
int f = q.top().second;
q.pop();
if(use[f])
continue;
use[f] = 1;
int mx = max(dist[f],dis[f]);
for(int i = head[f] ; i ; i = next[i])
if(mx + l[i].d < dist[l[i].t])
{
dist[l[i].t] = mx + l[i].d;
int tmp = max(dist[l[i].t],dis[l[i].t]);
if(pd(l[i].t))
q.push(make_pair(tmp,l[i].t));
}
for(int i = 1 ; i <= nu[f] ; i ++)
{
int t = map[f][i];
num[t] --;
dis[t] = max(dis[t],mx);
int tmp = max(dist[t],dis[t]);
if(pd(t))
q.push(make_pair(tmp,t));
}
}
printf("%d\n",max(dis[n],dist[n]));
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= n ; i ++)
dist[i] = 214748364;
for(int i = 1 ; i <= m ; i ++)
{
int f,t,d;
scanf("%d%d%d",&f,&t,&d);
if(f != t)
build(f,t,d);
}
for(int i = 1 ; i <= n ; i ++)
{
int li;
scanf("%d",&li);
num[i] = li;
for(int j = 1 ; j <= li ; j ++)
{
int pro;
scanf("%d",&pro);
map[pro][++nu[pro]] = i;
}
}
dijkstra();
return 0;
}
传送门 :
codevs2310
bzoj1922