二进制分组也可以说是一种比较优美的拆贡献方式吧?

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

HINT

[样例解释]

对于第一个数据:路径为1->2->3->1,所需时间为8,而1->3->2->1所花时间为9。因此答案为8.

[数据范围与约定]

对于40%的数据:n<=1,000; m<=5,000

对于100%的数据:1<=n<=40,000; 1<=m<=100,000; 1<=v,w<=1,000


题目分析

首先考虑一些性质。对于不与1相连的边,由于边权为正,所以它们是一定不会经过多次的,那么这个限制相当于就去掉了。接下去的问题就出在与1相连的边这里,因为可能从同一条边出入1点最优。

朴素做法:指定一条出边和一条入边,每次计算答案。

考虑答案的出入边$i$和$j$,那么$i,j$一定有一个二进制位不同。于是我们枚举不同的二进制位,将该位为0/1的两类边分别分成出边/入边集合,做完一次dij就枚举入边统计答案。

时间复杂度:$O(n\log^2n)$.

后话:这个做法复杂度在这两题确实有点大了。两题差不多都拿了倒数前20吧。

 #include<bits/stdc++.h>
const int maxn = ;
const int maxm = ; struct Edge
{
int v,c;
Edge(int a=, int b=):v(a),c(b) {}
}edges[maxm];
struct node
{
int x,d;
node(int a=, int b=):x(a),d(b) {}
bool operator < (node a) const
{
return d > a.d;
}
};
int n,m,ans,dis[maxn],dfn[maxn],tim;
int edgeTot,head[maxn],nxt[maxm],tag[maxm];
std::priority_queue<node> q; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void addedge(int u, int v, int c)
{
edges[++edgeTot] = Edge(v, c), nxt[edgeTot] = head[u], head[u] = edgeTot;
}
void dijkstra()
{
memset(dis, 0x3f3f3f3f, sizeof dis);
++tim, q.push(node(, )), dis[] = ;
for (node tmp; q.size(); )
{
tmp = q.top(), q.pop();
if (dfn[tmp.x]==tim) continue;
dfn[tmp.x] = tim;
for (int i=head[tmp.x]; i!=-; i=nxt[i])
if (tag[i]!=-)
{
int v = edges[i].v;
if (dis[v] > dis[tmp.x]+edges[i].c)
dis[v] = dis[tmp.x]+edges[i].c, q.push(node(v, dis[v]));
}
}
for (int i=head[]; i!=-; i=nxt[i])
if (tag[i]==-&&(ans==-||(ans > dis[edges[i].v]+edges[i^].c)))
ans = dis[edges[i].v]+edges[i^].c;
}
int main()
{
memset(head, -, sizeof head);
n = read(), m = read(), ans = edgeTot = -;
for (int i=; i<=m; i++)
{
int u = read(), v = read(), s = read(), t = read();
addedge(u, v, s), addedge(v, u, t);
}
for (int d=; d>=; --d)
{
for (int i=head[]; i!=-; i=nxt[i])
if ((i>>d)&) tag[i] = , tag[i^] = -;
else tag[i] = -, tag[i^] = ;
dijkstra();
for (int i=head[]; i!=-; i=nxt[i])
if ((i>>d)&) tag[i] = -, tag[i^] = ;
else tag[i] = , tag[i^] = -;
dijkstra();
}
printf("%d\n",ans);
return ;
}

END

最新文章

  1. 【日记】搭建一个node本地服务器
  2. 比较两个NSDate类型的参数相差的时间差
  3. Regular Expression Matching leetcode
  4. 排序稳定性stable
  5. mac10.7安装xcode3.2.5和xcode4.2过程和方法
  6. HDU 1009 FatMouse&#39; Trade(贪心)
  7. 第 8 章 IO库
  8. difference between collection and association mapping in mybatis 3
  9. photoKit使用笔记
  10. git 入门与应用
  11. html模板输头部出现&quot;&amp;#65279&quot;
  12. sudo su 和 sudo -s【转】
  13. PAT (Advanced Level) Practise 1004 解题报告
  14. Dedecms5.7搜索结果页空白无内容的解决方法
  15. sklearn中的数据集的划分
  16. PHP适配器模式
  17. java测试感想
  18. 开源的DirectUI界面库
  19. Zookeeper的shell操作
  20. Springmvc ajax请求400

热门文章

  1. PHP学习(5)——字符串操作与POSIX正则
  2. Linux正则表达式题型
  3. Python全栈开发之6、面向对象
  4. SpringBoot项目在IDEA中以jar方式部署
  5. Loj 2230. 「BJOI2014」大融合 (LCT 维护子树信息)
  6. 10.hive安装
  7. JS实现点击查看密码功能,再次点击隐藏密码!
  8. 树莓派驱动开发 helloworld
  9. jmeter 工具学习 未完待续
  10. MVC4中去掉浏览器生成的无关代码方法