[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)的更多相关文章

  1. luogu P2962 [USACO09NOV]灯Lights 高斯消元

    目录 题目链接 题解 题目链接 luogu P2962 [USACO09NOV]灯Lights 题解 可以折半搜索 map合并 复杂度 2^(n / 2)*logn 高斯消元后得到每个点的翻转状态 爆 ...

  2. meet in the middle 折半搜索 刷题记录

    复杂度分析 假设本来是n层,本来复杂度是O(2^n),如果meet in middle那就是n/2层,那复杂度变为O( 2^(n/2) ),跟原来的复杂度相比就相当于开了个方 比如如果n=40那爆搜2 ...

  3. [CSP-S模拟测试]:答题(meet in the middle)

    题目传送门(内部题142) 输入格式 输入文件的第一行为两个数$n,P$. 接下来一行$n$为个正整数,表示每道题的分数. 输出格式 输出一行一个正整数,为至少需要获得的分数. 样例 样例输入: 2 ...

  4. Meet in the middle学习笔记

    Meet in the middle(MITM) Tags:搜索 作业部落 评论地址 PPT中会讲的很详细 当搜索的各项互不影响(如共\(n\)个物品前\(n/2\)个物品选不选和后\(n/2\)个物 ...

  5. Meet in the middle

    搜索是\(OI\)中一个十分基础也十分重要的部分,近年来搜索题目越来越少,逐渐淡出人们的视野.但一些对搜索的优化,例如\(A\)*,迭代加深依旧会不时出现.本文讨论另一种搜索--折半搜索\((meet ...

  6. SPOJ4580 ABCDEF(meet in the middle)

    题意 题目链接 Sol 发现abcdef是互不相关的 那么meet in the middle一下.先算出abc的,再算def的 注意d = 0的时候不合法(害我wa了两发..) #include&l ...

  7. codevs1735 方程的解数(meet in the middle)

    题意 题目链接 Sol 把前一半放在左边,后一半放在右边 meet in the middle一波 统计答案的时候开始想的是hash,然而MLE了两个点 实际上只要排序之后双指针扫一遍就行了 #inc ...

  8. 【BZOJ4800】[Ceoi2015]Ice Hockey World Championship (meet in the middle)

    [BZOJ4800][Ceoi2015]Ice Hockey World Championship (meet in the middle) 题面 BZOJ 洛谷 题解 裸题吧,顺手写一下... #i ...

  9. 【CF888E】Maximum Subsequence(meet in the middle)

    [CF888E]Maximum Subsequence(meet in the middle) 题面 CF 洛谷 题解 把所有数分一下,然后\(meet\ in\ the\ middle\)做就好了. ...

  10. 【CF912E】Prime Game(meet in the middle)

    [CF912E]Prime Game(meet in the middle) 题面 CF 懒得翻译了. 题解 一眼题. \(meet\ in\ the\ middle\)分别爆算所有可行的两组质数,然 ...

随机推荐

  1. PL/SQL Initialization error Could not initialize 问题

    问题: PL/SQL Initialization error Could not initialize 问题 参考链接: https://blog.csdn.net/luoyanjiewade/ar ...

  2. vue 页面中切换国际语言

    1.npm i vue-i18n 2. 3.main.js 4.vue页面

  3. mongoengine模型字段非严格校验FieldDoesNotExist

    背景 最近需要从mongoDB中查询数据用于数据分析,一开始就用了pymongo后来发现使用起来很不方便,后面了解到有类似SQLAlchemy的ORM模块mongoengine能够操mongo 简单看 ...

  4. mac SIP系统完整性保护关闭方法

    许多Mac用户反应,装了部分软件后打不开,那可能是sip系统完整性没有关闭.下面我们就来看一下如何关闭sip系统完整性. 检查状态 在sip系统完整性关闭前,我们先检查是否启用了SIP系统完整性保护. ...

  5. sql中exists用法

    exists关键字介绍 exists强调的是 是否返回结果集,不要求知道返回什么,比如: SELECT * FROM AM_USER WHERE EXISTS (SELECT 1 FROM AM_RO ...

  6. 关于Windows系统TCP参数修改

    在做压测时,往往会因为TCP连接数较少,导致并发数上不去就报错,下面我们一起看看如何修改Windows的TCP参数 1.本地注册表 打开注册表快捷键:Windows+R建,输入regedit,按下键盘 ...

  7. Android Studio实现数据库的所有操作

    采用android studio自带的数据库实现stu数据库和stu表的创建,增删改查和关闭 这是项目的大致结构 主界面 子界面 布局源码 <!-- Main --> <?xml v ...

  8. OSI网络七层模型简明教程

    如果你读过计算机专业,或者学习过网络通信,那你一定听说过 OSI 模型,它曾无数次让你头大.OSI 是 Open System Interconnection 的缩写,译为"开放式系统互联& ...

  9. 使用jquery+layui 做一个输入搜索下拉 类似lay-search

    效  果: 因为需要做一个搜索出现下拉然后点击 自动填装input 内容的 东西. 一开始使用lay-search 的控件去弄. 但是无法控制里面的内容.所以用了一些笨方法去弄 废话不说了, html ...

  10. CF1561D Up the Strip

    Up the Strip 题意 你现在在 \(n\) 号格子,你需要跳到 \(1\) 号格子,你可以有两种跳法: 你可以做减法,即选择一个数 \(k\in [1,n)\) ,从 \(n\) 跳到 \( ...