mcfx's blog - 最短路 /category/zd/ BZOJ 4398: 福慧双修 /archives/158/ 2016-12-26T10:48:00+08:00 ###Description 菩萨为行,福慧双修,智人得果,不忘其本。 ——唐朠立《大慈恩寺三藏法师传》 有才而知进退,福慧双修,这才难得。 ——乌雅氏 如何福慧双修?被太后教导的甄嬛徘徊在御花园当中。突然,她发现御花园中的花朵全都是红色和蓝色的。她冥冥之中得到了响应:这就是指导她如何福慧双修的! 现在御花园可以看作是有N块区域,M条小路,两块区域之间可通过小路连接起来。现在甄嬛站在1号区域,而她需要在御花园中绕一绕,且至少经过1个非1号区 域的区域。但是恰好1号区域离碎玉轩最近,因此她最后还是要回到1号区域。由于太后教导她要福慧双修,因此,甄嬛不能走过任何一条她曾经走过的路。但是, 御花园中来往的奴才们太多了,而且奴才们前行的方向也不一样,因此甄嬛在走某条小路的时候,方向不同所花的时间不一定一样。天色快暗了,甄嬛需要尽快知道 至少需要花多少时间才能学会如何福慧双修。如果甄嬛无法达到目的,输出“-1”。 ###Input 第一行仅2个正整数n,m,意义如题。 接下来m行每行4个正整数s,t,v,w,其中s,t为小路所连接的两个区域的编号,v为甄嬛从s到t所需的时间,w为甄嬛从t到s所需的时间。数据保证无重边。 ###Output 仅一行,为甄嬛回到1号区域所需的最短时间,若方案不存在,则输出-1 ###Sample Input 3 3 1 2 2 3 2 3 1 4 3 1 5 2 ###Sample Output 8 ###Solution 一条合法路径一定是1->a->...->b->1这样的 考虑a和b一定有至少一个二进制位不同 所以按二进制分组,每次新建一个源点和汇点,分别连向某位为1和0的点,然后跑最短路 ###Code ```c++ #include #define mp(a,b) std::make_pair(a,b) int n,p[40001],dis[40001]; bool vis[40001]; std::priority_queueq; struct edge { int to,ne,w; }e[200001]; inline void add(int i,int a,int b,int w) { e[i].to=b,e[i].ne=p[a],e[i].w=w,p[a]=i; } inline void yjq(int andv,int anda,int &ans) { memset(dis,0x7f,sizeof(dis)); memset(vis,0,sizeof(vis)); for(int j=p[1];j;j=e[j].ne) if((e[j].to&andv)==anda) q.push(mp(dis[e[j].to]=e[j].w,e[j].to)); while(!q.empty()) { int k=q.top().second;q.pop(); if(vis[k])continue; vis[k]=1; for(int j=p[k];j;j=e[j].ne) if(e[j].to==1) { if((k&andv)!=anda&&ans>dis[k]+e[j].w)ans=std::min(ans,dis[k]+e[j].w); } else if(dis[e[j].to]>dis[k]+e[j].w) { q.push(mp(dis[e[j].to]=dis[k]+e[j].w,e[j].to)); } } } int main() { int m; scanf("%d%d",&n,&m); for(int i=0;i