【xsy1162】鬼计之夜 最短路+二进制拆分

套路题(然而我没看题解做不出来)

题目大意:给你一个$n$个点,$m$条有向边的图。图中有$k$个标记点,求距离最近的标记点间距离。

数据范围:$n,m,k≤10^5$。

设$p_i表$示第$i$个标记点的编号,设$K$为最小正整数,满足$2^K≥k$。

我们在原图中新建点$S$和点$T$,做$2K$次最短路。

对于$K$个二进制位,将$k$个关键点分成两部分,以其中一部分为起点,向另一部分做最短路即可。

时间复杂度:$O(m\ \log\ n\ \log k)$

 #include<bits/stdc++.h>
#define M 200005
#define L long long
#define INF (1LL<<60)
using namespace std; struct edge{L u,v,next;}e[M*]={}; L head[M]={},use=;
void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
L vis[M]={},S,T,n,m,k; struct node{
L u,dis; node(){u=dis=;}
node(L U,L Dis){u=U; dis=Dis;}
friend bool operator <(node a,node b){return a.dis>b.dis;}
};priority_queue<node> q; L bfs(){
memset(vis,,sizeof(vis));
q.push(node(S,));
while(!q.empty()){
node U=q.top(); q.pop();
if(U.u==T) return U.dis;
if(vis[U.u]) continue;
vis[U.u]=;
for(L i=head[U.u];i;i=e[i].next)
if(vis[e[i].u]==)
q.push(node(e[i].u,U.dis+e[i].v));
}
return INF;
}
L u[M]={},v[M]={},w[M]={},id[M]={};
main(){
scanf("%lld%lld%lld",&n,&m,&k); S=; T=n+;
for(L i=;i<=m;i++) scanf("%lld%lld%lld",u+i,v+i,w+i);
for(L i=;i<=k;i++) scanf("%lld",id+i);
L ans=INF;
for(L p=;p<=k;p<<=){
memset(head,,sizeof(head)); use=;
for(L i=;i<=m;i++) add(u[i],v[i],w[i]);
for(L i=;i<=k;i++)
if(p&i) add(S,id[i],);
else add(id[i],T,);
ans=min(ans,bfs()); memset(head,,sizeof(head)); use=;
for(L i=;i<=m;i++) add(u[i],v[i],w[i]);
for(L i=;i<=k;i++)
if(p&i) add(id[i],T,);
else add(S,id[i],);
ans=min(ans,bfs());
}
cout<<ans<<endl;
}
上一篇:iOS缓存框架-PINCache解读


下一篇:Eclipse console文本换行