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\)分别爆算所有可行的两组质数,然 ...
随机推荐
- HttpClient详细使用示例(转)
https://blog.csdn.net/justry_deng/article/details/81042379
- using Spire.Pdf 合并文件夹下.pdf 文件
using Spire.Pdf private void mergePDF() { List<string> filesList = new List<string>(); D ...
- ICPC2020上海B - Mine Sweeper II
思维 [B-Mine Sweeper II_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)(重现赛)@hzy0227 (nowcoder.com)](https://codeforc ...
- ES6新增运算符 ?? || &&
运算符(?? || &&) && 与运算符 &&左边表达式为真时执行右边表达式 let a = true let b = 0 a && ...
- Java基础之标识符和关键字
关键字 标识符 Java所有的组成部分都需要名字.类名.变量名以及方法名都被称为标识符. Java 中标识符是为方法.变量或其他用户定义项所定义的名称.标识符可以有一个或多个字符. 标识符注意点: 在 ...
- 页面-vue-功能
一. 数组添加/修改数据 使用map this.list.map(i => { i.show = false return i }) 使用foreach this.list.forEach(i ...
- Mysterious-GIF --- 攻防世界WP
题目描述: 附件: ps:我重命名了一下为 cindy,gif 解题过程 1.分析该GIF (1)查看图片属性 (2)strings命令查找字符串 (3)winhex查看 (4)因为是GIF,所以可使 ...
- lui - pager - 分页
pager - 分页 demo lui demo <template> <div class="app-container"> <h3>el-p ...
- docker-compose之memcached
新建docker-compose.yml,写入以下内容 memcached: image: memcached:latest ports: - 11211:11211 启动服务 docker-comp ...
- 我的第二次JAVA作业
1. Java包含哪两大类数据类型?其中基本类型的每种类型的取值范围和默认值分别是多少?请编程验证. Java 的两大数据类型: 基本类型 引用类 基本数据类型: 整数类型: byte: byte 数 ...