HDU 5544 Ba Gua Zhen ( 2015 CCPC 南阳 C、DFS+时间戳搜独立回路、线性基 )
题意 : 给出一副简单图、要你找出一个回路、使得其路径上边权的异或和最大
分析 :
类似的题有 BZOJ 2115
对于这种异或最长路的题目(走过的边可以重复走)
答案必定是由一条简单路径(链) + 一些基本环构成
这是因为操作是 xor , 具有自反性质 , 可能需要脑补一下
回到这题, 发现答案就是要求找出一个环
那么根据上面那道题目的启发
答案是一个环的情况下, 那么答案环必定也是由其他环来组成
那么只要找出图中所有的基本环, 就可以由这些基本环来线性组合出最大 xor 环了
有一个定理
对于一个图而言、其独立回路的个数为 M - N + 1
独立回路是指任意一个都不能由其他回路构成。
引用一段数学归纳法证明:
“M=N-1时,树,结论成立
设M=K时结论成立,当M=K+1时,任取G中一条边e,G-e中有K-N+1个独立回路,且
任取一个包含e的回路C,显然独立于之前的回路
任意两个包含e的回路C1与C2,C12=C1+C2是G-e的回路,C2不独立
故能且仅能增加一个包含e的独立回路
从而G中恰有(K+1)-N+1个独立回路,证毕”
红色字体引用自 ==> Click here
即一个图最多只有 M + ( N - 1 ) 个独立回路 (即基本环)
而除开独立回路外的图中剩余所有回路都能被这 M - N + 1 个独立回路线性表示
那么由于异或拥有自反性质、即走过两遍的路径不会产生贡献
接下来如果能找出所有的独立回路、这样问题就变成了、给出 N 个数
从中找出异或和最大的组合、这个可以用线性基轻松做到
如何用DFS找出图中所有的独立回路?
首先你考虑生成树, 对于一个图的生成树而言
其基本环(不能由其他环线性表示的环)就是任意两个树上节点 + 非树边构成
那么先 DFS 出生成树, 加上时间戳, 若干当前节点的时间戳大于被遍历到的节点的时间戳
则说明找到一个上面那样子的非树边, 即找到了一个基本环
这样子找出来的环正好有 M - ( N - 1 ) 即所有的边 - 树边这么多
参考自 ==> Click here , Click here
#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define scl(i) scanf("%lld", &i)
#define scll(i, j) scanf("%lld %lld", &i, &j)
#define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
#define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)
#define scs(i) scanf("%s", i)
#define sci(i) scanf("%d", &i)
#define scd(i) scanf("%lf", &i)
#define scIl(i) scanf("%I64d", &i)
#define scii(i, j) scanf("%d %d", &i, &j)
#define scdd(i, j) scanf("%lf %lf", &i, &j)
#define scIll(i, j) scanf("%I64d %I64d", &i, &j)
#define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
#define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
#define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
#define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
#define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
#define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define lowbit(i) (i & (-i))
#define mem(i, j) memset(i, j, sizeof(i))
#define fir first
#define sec second
#define VI vector<int>
#define ins(i) insert(i)
#define pb(i) push_back(i)
#define pii pair<int, int>
#define VL vector<long long>
#define mk(i, j) make_pair(i, j)
#define all(i) i.begin(), i.end()
#define pll pair<long long, long long>
#define _TIME 0
#define _INPUT 0
#define _OUTPUT 0
clock_t START, END;
void __stTIME();
void __enTIME();
void __IOPUT();
using namespace std;
;
];
;
int n, m;
inline void EdgeInit()
{
mem(Head, -);
EdgeCnt = ;
}
inline void AddEdge(int from, int to, LL weight)
{
int & cnt = EdgeCnt;
Edge[cnt].v = to;
Edge[cnt].w = weight;
Edge[cnt].nxt = Head[from];
Head[from] = cnt++;
}
struct L_B {
LL d[], p[];
int cnt;
void init() {
memset(d, , sizeof(d));
memset(p, , sizeof(p));
cnt = ;
} // 1e18以内的数都适用.
bool Insert(LL val) {
; i >= ; i --) {
if (val & (1ll << i)) {
if (!d[i]) {
d[i]=val;
break;
}
val^=d[i];
}
}
;
// 可判断val是否存在于线性基当中.
}
LL query_max() {
LL res = ;
; i >= ; i --) {
if ((res^d[i]) > res) res ^= d[i];
}
return res;
}
LL query_min() { // 应该预先判断能否是0的情况..QAQ
; i <= ; i ++) {
if (d[i]) return d[i];
}
;
}
void rebuild() { // 用于求第k小值.需要先进行独立预处理
; i >= ; i --) {
; j >= ; j --) {
if (d[i] & (1ll<<j)) d[i] ^= d[j];
}
}
; i <= ; i ++) {
if (d[i]) p[cnt++]=d[i];
}
}
LL kthquery(LL k) { // 注意判断原序列异或出0的情况, 此时应该将k -- 在进行后面的操作.
LL res = ;
;
; i >= ; i --) {
if (k & (1LL<<i)) res ^= p[i];
}
return res;
}
void Merge(const L_B &b) { // 把b这个线性基插入到当前这个线性基中.
; i >= ; i --)
if (b.d[i]) Insert(b.d[i]);
}
}LB;
int DFN[maxn];
int DFS_Clocks;
LL val[maxn];
VL CycleVal;
inline void DFS(int u, int fa)
{
DFN[u] = ++DFS_Clocks;
vis[u] = true;
for(int i=Head[u]; ~i; i=Edge[i].nxt){
int v = Edge[i].v;
if(v == fa) continue;
if(vis[v] && DFN[v] < DFS_Clocks){///若当前当前点的时间戳大于出度点、则说明找到一条回路
CycleVal.pb(val[v] ^ val[u] ^ Edge[i].w);
}else if(!vis[v]){
val[v] = val[u] ^ Edge[i].w;
DFS(v, u);
}
}
}
int main(void){__stTIME();__IOPUT();
int nCase;
sci(nCase);
; Case<=nCase; Case++){
scii(n, m);
EdgeInit();
; i<=m; i++){
int u, v;
scii(u, v);
LL w;
scl(w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
CycleVal.clear();
; i<=n; i++)
vis[i] = false,
val[i] = 0LL;
DFS_Clocks = ;
; i<=n; i++)
if(!vis[i])
DFS(i, -);
LB.init();
; i<(int)CycleVal.size(); i++)
LB.Insert(CycleVal[i]);
printf("Case #%d: %lld\n", Case, LB.query_max());
}
__enTIME();;}
void __stTIME()
{
#if _TIME
START = clock();
#endif
}
void __enTIME()
{
#if _TIME
END = clock();
cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
#endif
}
void __IOPUT()
{
#if _INPUT
freopen("in.txt", "r", stdin);
#endif
#if _OUTPUT
freopen("out.txt", "w", stdout);
#endif
}
顺带一提, 找出图中所有的简单环, 这个东西是 NP 的, 正是由于 xor
有自反这种美妙的性质, 才能通过基本环+线性基来做这题
求出图中所有环数量的算法, 也是考虑通过生成树的方法 ==> Click here
Codeforces 也有过一道题目, 要求找出环的数量, 标算是状压 ==> Click here
HDU 5544 Ba Gua Zhen ( 2015 CCPC 南阳 C、DFS+时间戳搜独立回路、线性基 )的更多相关文章
- HDU 5544 Ba Gua Zhen dfs+高斯消元
Ba Gua Zhen Problem Description During the Three-Kingdom period, there was a general named Xun Lu wh ...
- The 2015 China Collegiate Programming Contest E. Ba Gua Zhen hdu 5544
Ba Gua Zhen Time Limit: 6000/4000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total ...
- 2015南阳CCPC E - Ba Gua Zhen 高斯消元 xor最大
Ba Gua Zhen Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 无 Description During the Three-Kingdom perio ...
- Ba Gua Zhen
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5544 学习链接:https://www.cnblogs.com/qscqesze/p/4902518. ...
- ACM学习历程—UESTC 1219 Ba Gua Zhen(dfs && 独立回路 && xor高斯消元)
题目链接:http://acm.uestc.edu.cn/#/problem/show/1219 题目大意是给了一张图,然后要求一个点通过路径回到这个点,使得xor和最大. 这是CCPC南阳站的一道题 ...
- hdu 3949 XOR (线性基)
链接: http://acm.hdu.edu.cn/showproblem.php?pid=3949 题意: 给出n个数,从中任意取几个数字异或,求第k小的异或和 思路: 线性基求第k小异或和,因为题 ...
- HDU 4403 A very hard Aoshu problem(dfs爆搜)
http://acm.hdu.edu.cn/showproblem.php?pid=4403 题意: 给出一串数字,在里面添加一个等号和多个+号,使得等式成立,问有多少种不同的式子. 思路: 数据量比 ...
- HDU 3949 XOR 线性基
http://acm.hdu.edu.cn/showproblem.php?pid=3949 求异或第k小,结论是第k小就是 k二进制的第i位为1就把i位的线性基异或上去. 但是这道题和上一道线性基不 ...
- -【线性基】【BZOJ 2460】【BZOJ 2115】【HDU 3949】
[把三道我做过的线性基题目放在一起总结一下,代码都挺简单,主要就是贪心思想和异或的高斯消元] [然后把网上的讲解归纳一下] 1.线性基: 若干数的线性基是一组数a1,a2,a3...an,其中ax的最 ...
随机推荐
- COGS 2633. [HZOI 2016] 数列操作e
[题目描述] 一个长度为n的序列,一开始序列数的权值都是0,有m次操作 支持两种操作, 1 L R x,给区间[L,R]内,第一个数加x,第二个数加2^2⋅x,第三个数加3^2⋅x...第R-L+1个 ...
- QT 打包exe
QT打包主要方法: 1.把无措的代码进行Release编译 2.在运行完后,找到运行后生成的目录,以下是我的文件,名为result,运行类型有两种,一种是Debug,另一种是Release,我们需要的 ...
- Redis 和 Memcached 各有什么优缺点,主要的应用场景是什么样的?
1.显示最新的项目列表 2.删除与过滤 3.排行榜相关 4.按照用户投票和时间排序 5.处理过期项目 6.计数 7.特定时间内的特定项目 8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等 9. ...
- django中的缓存 跨域问题(同源策略)
django缓存机制 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作 ...
- Docker 常用命令和Dockerfile
Docker 简介 官方的解释为:Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现 ...
- gdb暂停或恢复程序的运行
ref : https://blog.csdn.net/seu_lyr/article/details/9050657 一 暂停程序的运行: (一)GDB的暂停方式:断点(BreakPoint). ...
- android中sqlite数据库的基本使用和添加多张表
看了很多关于android使用sqlite数据库的文章,很多都是介绍了数据库的建立和表的建立,而表通常都是只建立一张,而实际情况我们用到的表可能不止一张,那这种情况下我们又该怎么办呢,好了,下面我教大 ...
- 微信公众号支付备忘及填坑之路-java
一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...
- IOC之MEF学习
MEF原理上很简单,找出有共同接口的导入.导出.然后找到把导出的实例化,赋给导入.说到底MEF就是找到合适的类实例化,把它交给导入.Export 特性可修饰类.字段.属性或方法,而 Import 特性 ...
- javaIO——PipedReader 和 PipedWriter 实现模拟即时聊天
上一篇学习了javaIO里面的 PipedReader 和 PipedWriter,这里对两个类做一个小小的练习:实现一个即时消息发送和接收的聊天系统(这里只实现单向发送,双向同理,定义两个管道即可) ...