~~~题面~~~

题解:

  考场上看的这道题,,,当时70分算法打挂了,今天才知道这个也是原题。。。。

  首先,对于不跟1相邻的边,肯定不会经过两次,因为经过两次就回来了,除了增加路径长度之外没有任何意义。

  但是跟1相邻的边是可能会经过2次的,因为虽然增加了路径长度,但这次回来就直接到终点了,所以完全可能重复走。

  那么有一个很容易发现的思路是,我们可以强制某一条边是出边(即从1点出去可以走的边),其他边则为入边,这样的话就可以强制走不同的路了,但这样时间复杂度较大。考虑优化它。

  可以发现,这样分组的本质就是要使得对于任意二元组(x, y)而言,x和y都至少要有两次被分配在不同的集合中,这样它们才可以互相搭配组成两条可能的路径。

  为什么是两条呢?

  对于相同的路径而言,分两个方向走一遍权值是不同的,也就是说对于这条路径:1 --- 2 --- 4 --- 3 --- 1,我既可以1 ---> 2 ---> 4 ---> 3 ---> 1,也可以1 <--- 2 <--- 4 <---  3 <--- 1.如果只是单纯的把2,3两条边分在不同的集合当中,你根本不知道会找到哪条路径,也不知道是否这条路径刚好就是最优的那条。

  观察到任意边的编号都是不同的,这意味这它们对应的二进制串至少有一位是不同的,所以我们可以枚举位数,按照当前位是0还是1给边分组,那么由于任意两个串对于的二进制串都至少有一位不同,因此它们一定会有一次被分在不同的集合当中。因为我们需要找到所有可能路径,所以要把当前位是0的分给s1和当前位是0的分给s2都试一遍才能保证正确性。

  但实际上你会发现不用试2遍也可以过这道题,这是数据原因,,,因为我已经把我原来那份代码给hack掉了。。。。

  因为你可以发现,会发生错误的几率是很低的,因为发生错误当且仅当对应的最短路径没有被找到,而这种情况出现在1号点对应的出边和入边的编号刚好所有不同的地方都是1 对 0或者0 对1,并且刚好那个1 对 0(0对1)就会将2条边分在错误的集合。

  所以除非构造数据来卡,不然出现错误的可能性是很低的。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define LL long long
  5 #define AC 50100
  6 #define ac 401000
  7
  8 int n, m, t, ans = INT_MAX, k;
  9 int dis[AC], s[ac], top;
 10 int Head[AC], date[ac], Next[ac], len[ac], tot = 1;
 11 bool vis[AC];
 12
 13 struct road{
 14     int x, y, dis1, dis2;
 15 }way[ac];
 16
 17 struct node{
 18     int dis, id;
 19 };
 20
 21 struct cmp{
 22     bool operator () (node a, node b)
 23     {
 24         return a.dis > b.dis;
 25     }
 26 };
 27 priority_queue<node, vector<node>, cmp> q;
 28
 29 inline int read()
 30 {
 31     int x = 0;char c = getchar();bool z = false;
 32     while(c > '9' || c < '0')
 33     {
 34         if(c == '-') z = true;
 35         c = getchar();
 36     }
 37     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 38     if(!z) return x;
 39     else return -x;
 40 }
 41
 42 inline void upmin(int &a, int b)
 43 {
 44     if(b < a) a = b;
 45 }
 46
 47 inline void upmax(int &a, int b)
 48 {
 49     if(b > a) a = b;
 50 }
 51
 52 inline void add(int f, int w, int S)
 53 {
 54     if(w == 1) w = t;
 55     date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S;
 56     //printf("%d ---> %d : %d\n", f, w, S);
 57 }
 58
 59 void pre()
 60 {
 61     n = read(), m = read(), t = n + 1;
 62     for(R i = 1; i <= m; i ++)
 63     {
 64         way[i].x = read(), way[i].y = read(), way[i].dis1 = read(), way[i].dis2 = read();
 65         if(way[i].x == 1 || way[i].y == 1) s[++top] = i;
 66     }
 67 }
 68
 69 void build(int x)
 70 {
 71     //printf("%d:\n", x);
 72     int l = 1;
 73     tot = 0;
 74     memset(Head, 0, sizeof(Head));
 75     for(R i = 1; i <= m; i ++)
 76     {
 77         if(i == s[l])
 78         {
 79             if(k ^ (l & x))//不仅仅要被分在不同集合当中,
 80             {//还需要x1s1 + x2s2 ; x1s2 + x2x1两种情况都出现一次才能包括所有的情况
 81                 if(way[i].x == 1) add(way[i].x, way[i].y, way[i].dis1);
 82                 else add(way[i].y, way[i].x, way[i].dis2);
 83             }
 84             else
 85             {
 86                 if(way[i].x == 1) add(way[i].y, way[i].x, way[i].dis2);
 87                 else add(way[i].x, way[i].y, way[i].dis1);
 88             }
 89             l ++;
 90         }
 91         else
 92         {
 93             add(way[i].x, way[i].y, way[i].dis1);
 94             add(way[i].y, way[i].x, way[i].dis2);
 95         }
 96     }
 97 }
 98
 99 void spfa()
100 {
101     int x, now;
102     memset(dis, 127, sizeof(dis));
103     memset(vis, 0, sizeof(vis));
104     dis[1] = 0;
105     q.push((node){0, 1});
106     while(!q.empty())
107     {
108         x = q.top().id, q.pop();
109         while(vis[x] && !q.empty()) x = q.top().id, q.pop();
110         if(vis[x]) break;
111         vis[x] = true;
112         for(R i = Head[x]; i; i = Next[i])
113         {
114             now = date[i];
115             if(dis[now] > dis[x] + len[i])
116             {
117                 dis[now] = dis[x] + len[i];
118                 q.push((node){dis[now], now});
119             }
120         }
121     }
122     upmin(ans, dis[t]);
123 }
124
125 void work()
126 {
127     int tmp = 1;
128     for(R i = 0; i <= 17; i ++)
129     {
130         k = 1, build(tmp), spfa();
131         k = 0, build(tmp), spfa();
132         tmp <<= 1;
133     }
134     printf("%d\n", ans);
135 }
136
137 int main()
138 {
139     freopen("in.in", "r", stdin);
140     pre();
141     work();
142     fclose(stdin);
143     return 0;
144 }

View Code

转载于:https://www.cnblogs.com/ww3113306/p/9802823.html

[bzoj4398] 福慧双修 最短路 二进制分组相关推荐

  1. 【BZOJ2069】ZAW(POI2004)-最短路+二进制分组

    测试地址:ZAW 题目大意: 给定一张边是双向的图,一条边走不同的方向可能代价不同,代价都非负,求从点111出发,不经过重复的点或边的最小回路.n≤5000,m≤10000n\le 5000,m\le ...

  2. hdu-6166(最短路+二进制分组)

    题意:给你n个点m条边的有向图,然后再给你k个不同的点,问你这k个点的最小距离: 解题思路:这道题最需要注意的就是k个点一定是不同的,那么有一个结论就是任意两个不同的数字中,在他们的二进制地表示中,一 ...

  3. BZOJ2407:探险/BZOJ4398:福慧双修-最短路+分治

    两道都是权限题- 题意: 给出一张n个点,m条边的图,同一条边不能走两次,每条边正着走与反着走所需要的时间可能不同,求一个从1开始的大于一个点的最短环 N<=10000,M<=200000 ...

  4. bzoj#2407-探险【最短路,二进制分组】

    正题 题目链接:https://darkbzoj.tk/problem/2407 题目大意 nnn个点的一张无向图(但是正反权值不同),求一个从111出发回到111且不经过重复边的最短路径. 1≤n≤ ...

  5. 【技巧 二进制分组】bzoj4398: 福慧双修2407: 探险

    二进制分组也可以说是一种比较优美的拆贡献方式吧? Description 菩萨为行,福慧双修,智人得果,不忘其本. --唐朠立<大慈恩寺三藏法师传> 有才而知进退,福慧双修,这才难得. - ...

  6. bzoj 4398 福慧双修——二进制分组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4398 如果枚举1号点走哪些点出去,就从那些点出发跑多源最短路即可.最短路不会重复经过一条边. ...

  7. [bzoj4398]福慧双修

    [bzoj4398]福慧双修 要求不能走重复的边,路径就是1->u->v->1,然后我们可以i想到一个暴力:把1去掉 枚举u跑最短路然后枚举v更新答案.因为边权非负,这个肯定是合法的 ...

  8. bzoj29894170数列——二进制分组+主席树

    题意的转化挺巧妙的 可以联想到曼哈顿距离! 并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗? 看成(x,a[x])的点 就是一个菱形区域 转切比雪夫距离,变成矩形 ...

  9. 【BZOJ3821/UOJ46】玄学(二进制分组,线段树)

    [BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...

最新文章

  1. ADSL防御******的十大方法
  2. ES6箭头函数和模板字符串
  3. SAP Spartacus CmsService的CmsActions.LoadCmsComponent
  4. 【渝粤题库】国家开放大学2021春1398分析化学(本)题目
  5. 从0到1使用VUE-CLI3开发实战(五):模块化VUEX及使用vuetify
  6. 2020.10.s1 冯上
  7. SQL Server时间粒度系列----第4节季、年时间粒度详解
  8. 吴恩达深度学习课程第四章第二周编程作业(pytorch实现)
  9. C++程序设计原理与实践(第二版)思考题答案
  10. 高校实验室安全隐患及安全建设-LIMS2
  11. 扬州大学复试1301软件工程【自制题库个人复习用】
  12. 计算机键盘没有fn,键盘Fn键失灵怎么解决?键盘Fn键失灵的修复方法
  13. python九宫格拼图_利用Python实现朋友圈中的九宫格图片效果
  14. 使用file.delete删除文件不起作用解决办法
  15. 嵌入式行业技术思维导图
  16. Captcha Cracker (java)附带replace用法
  17. 【JY】西南交通大学柔性防护:边坡地质动力灾害柔性防护仿真
  18. SPSS多元线性回归残差分析的基本方法
  19. android ios 实时视频,Twitter推出适用于Android和iOS设备的实时视频
  20. 只要8元,就能体验美国第一夫人的乐趣

热门文章

  1. 梅西百货将VR技术更融入生活 加入App功能中提升用户体验
  2. 2021年茶艺师(中级)考试报名及茶艺师(中级)考试试卷
  3. at指令 meid_MTK平台手机写IMEI的方法
  4. PaperTigerOS(第四天)
  5. Delphi/C#之父Anders Hejlsberg
  6. python函数参数之必选参数,默认参数,可变参数,关键字参数
  7. 使用Docker国内镜像源
  8. 圈铁发音,动感与无噪强强出彩,魔浪HIFIair蓝牙耳机测评
  9. 关键词4K图片采集下载软件【非常适合做电脑壁纸等】
  10. 荣刚:中国航信数据中心与灾备中心的运行