P2962 [USACO09NOV]Lights G(Meet In The Middle)
[USACO09NOV]Lights G
题目描述
给出一张n个点n条边的无向图,每个点的初始状态都为0。
你可以操作任意一个点,操作结束后该点以及所有与该点相邻的点的状态都会改变,由0变成1或由1变成0。
你需要求出最少的操作次数,使得在所有操作完成之后所有n个点的状态都是1。
输入格式
第一行两个整数n, m
之后m行,每行两个整数a, b,表示在点a, b之间有一条边。
输出格式
一行一个整数,表示最少需要的操作次数。
样例
样例输入
5 6
1 2
1 3
4 2
3 4
2 5
5 3
样例输出
3
思路
使用Meet In The Middle,先将1~mid点的全部情况遍历,将可能得到的结果以及到达对应结果状态所需要的最少步数记录下来,由于1<<35过大,所以推荐使用map进行存储。
将前半部分遍历完成后遍历后半部分,对于每个操作可以得到一个最终状态,将最终状态与全1情况异或可以得到对应的互补状态,然后维护最小操作次数即可。
易错点
1.左移的时候记得使用1ll,不然会爆int。
2.需要初始化map[0] = 0,不然当后半能达到全1状态时会多加上几次操作(前半到达全0的次小操作次数)
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int> edge[50];
int N, M, ans;
map<int, int> half;
bool option(int op, int n)
{
//查看是否对第n位进行操作
return (op >> n) & 1;
}
int answer(int a)
{
//得到互补状态
return ans ^ a;
}
bool getState(int op, int n)
{
/*
判断当前位在某种操作下最终状态是0还是1
*/
int res = 0;
if(option(op, n)){
res += 1;
}
for(int i = 0; i < edge[n].size(); i++){
if(option(op, edge[n][i])) res += 1;
}
return (res & 1)?true:false;
}
int getOptionTime(int op)
{
/*
获得一个操作的总操作次数
*/
int res = 0;
while(op){
res += (op & 1);
op >>= 1;
}
return res;
}
int setStateEnd(int op)
{
/*
获得一个操作对应的最终状态,返回对应二进制数
*/
int res = 0;
for(int i = 0; i < N; i++){
if(getState(op, i)){
res ^= (1ll << i);
}
}
return res;
}
/*void print(int a)
{
stack<int> s;
while(a){
s.push(a & 1);
a >>= 1;
}
while(s.size()){
cout << s.top();
s.pop();
}
cout <<endl;
}*/
signed main()
{
cin >> N >> M;
half[0] = 0;// 维护map[0] = 0
ans = (1ll << N) - 1;// ans对应的最终想要的状态,用于与得到的状态异或来获取另外的部分
int minTime = 0x3f3f3f3f;
for(int i = 0; i < M; i++){// 建边
int a, b;
cin >> a >> b;
edge[--a].push_back(--b);
edge[b].push_back(a);
}
int mid = N >> 1ll;
for(int op = 0; op <= (1ll << (N/2))-1; op++){// 枚举前半部分的全部操作情况
int res = setStateEnd(op);// 得到操作情况对应的结果状态
//维护最小操作次数
if(half.count(res)){
half[res] = min(half[res], getOptionTime(op));
}
else{
half[res] = getOptionTime(op);
}
}
for(int op = 0; op <= (1ll << N)-(1ll << (N/2)); op += (1ll << (N/2))){// 枚举后半部分的全部操作情况
int res = setStateEnd(op);
int thisAns = answer(res);// 判断当前状态的互补状态
if(half.count(thisAns)){// 查看是否存在互补状态,若存在,则维护最小值
int nowTime = half[thisAns];
nowTime += getOptionTime(op);
minTime = min(minTime, nowTime);
}
}
/*cout << "------" << endl;
print(setStateEnd((1ll << 33) + (1ll << 34)));
print(ans);
cout << "------" << endl;
for(int i = 0; i < N; i++){
cout << i << "---->";
for(int j = 0; j <edge[i].size(); j++){
cout << edge[i][j] << ' ';
}
cout << endl;
}*/
cout << minTime <<endl;
return 0;
}
P2962 [USACO09NOV]Lights G(Meet In The Middle)的更多相关文章
- luogu P2962 [USACO09NOV]灯Lights 高斯消元
目录 题目链接 题解 题目链接 luogu P2962 [USACO09NOV]灯Lights 题解 可以折半搜索 map合并 复杂度 2^(n / 2)*logn 高斯消元后得到每个点的翻转状态 爆 ...
- meet in the middle 折半搜索 刷题记录
复杂度分析 假设本来是n层,本来复杂度是O(2^n),如果meet in middle那就是n/2层,那复杂度变为O( 2^(n/2) ),跟原来的复杂度相比就相当于开了个方 比如如果n=40那爆搜2 ...
- [CSP-S模拟测试]:答题(meet in the middle)
题目传送门(内部题142) 输入格式 输入文件的第一行为两个数$n,P$. 接下来一行$n$为个正整数,表示每道题的分数. 输出格式 输出一行一个正整数,为至少需要获得的分数. 样例 样例输入: 2 ...
- Meet in the middle学习笔记
Meet in the middle(MITM) Tags:搜索 作业部落 评论地址 PPT中会讲的很详细 当搜索的各项互不影响(如共\(n\)个物品前\(n/2\)个物品选不选和后\(n/2\)个物 ...
- Meet in the middle
搜索是\(OI\)中一个十分基础也十分重要的部分,近年来搜索题目越来越少,逐渐淡出人们的视野.但一些对搜索的优化,例如\(A\)*,迭代加深依旧会不时出现.本文讨论另一种搜索--折半搜索\((meet ...
- SPOJ4580 ABCDEF(meet in the middle)
题意 题目链接 Sol 发现abcdef是互不相关的 那么meet in the middle一下.先算出abc的,再算def的 注意d = 0的时候不合法(害我wa了两发..) #include&l ...
- codevs1735 方程的解数(meet in the middle)
题意 题目链接 Sol 把前一半放在左边,后一半放在右边 meet in the middle一波 统计答案的时候开始想的是hash,然而MLE了两个点 实际上只要排序之后双指针扫一遍就行了 #inc ...
- 【BZOJ4800】[Ceoi2015]Ice Hockey World Championship (meet in the middle)
[BZOJ4800][Ceoi2015]Ice Hockey World Championship (meet in the middle) 题面 BZOJ 洛谷 题解 裸题吧,顺手写一下... #i ...
- 【CF888E】Maximum Subsequence(meet in the middle)
[CF888E]Maximum Subsequence(meet in the middle) 题面 CF 洛谷 题解 把所有数分一下,然后\(meet\ in\ the\ middle\)做就好了. ...
- 【CF912E】Prime Game(meet in the middle)
[CF912E]Prime Game(meet in the middle) 题面 CF 懒得翻译了. 题解 一眼题. \(meet\ in\ the\ middle\)分别爆算所有可行的两组质数,然 ...
随机推荐
- yolov4 编译
参考教程:https://blog.csdn.net/weixin_45102257/article/details/108872951 问题: 
问题描述 1144. 递减元素使数组呈锯齿状 (Medium) 给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的值减少 1. 如果符合下列情况之一,则数组 A 就是 锯齿数组: ...
- Linux系统备份与还原——restore还原命令
之前有讲到Linux下的备份工具dump,有备份自然就有还原,而还原备份文件采用的命令则是restore restore命令格式: restore [模式] [选项] 模式: 有四种模式且不能混用,只 ...
- React脚手架的使用
初始化项目 npx create-react-app my-app // 或 npm init react-app my-app // 或 yarn create react-app my-app 启 ...
- Mac如何卸载软件 Mac如何删除软件
初次接触Mac苹果电脑的用户可能不知道如何卸载已经装好的应用软件,之前有给大家介绍Mac如何安装软件,现在教大家如何卸载软件,其实非常简单,让我们看看吧: 1.首先我们打开Finder,就是我们Doc ...
- mybatis动态生成sql示例
- python 深拷贝及浅拷贝区别
深拷贝及浅拷贝区别 浅拷贝copy: 可变类型:(列表,字典,集合)copy函数对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间进行存储,不会拷贝对象内部的子对象 不可变类型:(数字,字符 ...
- 在CentOS7中安装Redis
一.检查操作系统中是否安装gcc依赖 [root@192 bin]# yum list installed gcc 如果出现上面图片内容则是已经安装.(由于我是安装了的,所以会存在) 二.安装gcc- ...
- SpringIOC以及AOP注解开发
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作. 本质上:所有一切的操作都是 Java ...
- C# POST multipart/form-data 方式提交数据
一.提交方法 /// <summary> /// MultipartFormData Post方式提交 /// </summary> /// <param name=&q ...