CF_400_D
题目大意:给出n扇门,m把钥匙,和没把钥匙可以改变状态(关->开,开->关》)的门的数量及对应编号(保证每个门被两把钥匙控制),现给出n扇门的初始状态(1表示开,0表示关),问是否可以通过这m把钥匙(可用可不用,不一定用完)使得所有的门都开启。
题解:终于看到了2-sat的能想出来的题了,2-sat本质是满族解的判断,这题显然可以用2-sat来求解,求解的一般套路是将每个点拆为两个点,分别表示取或者不取(即一件事的正反两面),最后通过2-sat算法,判断是否可行。这题需要一个转化,即我们对m拆点,表示用或者不用这把钥匙改变对应的门。那么如何连边?可以这样想:对于一个门 的初始状态,如果是开,那么两把钥匙要么都用,要么都不用;如果是关,一定是用一把弃一把。那么就是说连边是要用门的初始状态确定的,那么这题也就解决了。
#pragma comment(linker, "/STACK: 1024000000,1024000000")
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define em emplace
#define pii pair<int,int>
#define de(x) cout << #x << " = " << x << endl
#define clr(a,b) memset(a,b,sizeof(a))
#define INF (0x3f3f3f3f)
#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
#define F first
#define S second
using namespace std;
inline int getint()
{
int _x=0; char _tc=getchar();
while(_tc<'0'||_tc>'9') _tc=getchar();
while(_tc>='0'&&_tc<='9') _x*=10,_x+=(_tc-'0'),_tc=getchar();
return _x;
}
const int N = 1e5 + 15;
int n, m;
int dor[N];
vector<int> key[N];
struct TwoSet
{
static const int MAXV = 100100;
int V, n, tp, S[MAXV<<1];
vector<int> g[MAXV<<1];
bool vis[MAXV<<1];
void init( int tt )
{
n = tt;
V = (tt<<1) + 1;
for ( int i = 1; i <= V; i ++ )
g[i].clear(), vis[i] = false;
}
void addEdge( int x, int y )
{
g[x].pb(y);
g[y].pb(x);
}
bool dfs( int x )
{
if ( vis[ x > n ? x - n : x + n ] ) return false;
if ( vis[x] ) return true;
vis[ S[++tp] = x ] = 1;
for ( int v : g[x] )
if ( !dfs(v) ) return false;
return true;
}
bool solve()
{
for ( int i = 1; i <= n; i ++ )
if ( !vis[i] && !vis[i+n] )
{
tp = 0;
if ( !dfs(i) )
{
while ( tp ) vis[S[tp--]] = false;
if ( !dfs(i+n) ) return false;
}
}
return true;
}
}TwoSet;
int main()
{
scanf("%d%d", &n, &m);
for ( int i = 1; i <= n; i ++ )
scanf("%d", &dor[i]);
for ( int i = 1, x; i <= m; i ++ )
{
scanf("%d", &x);
for ( int j = 0, y; j < x; j ++ )
scanf("%d", &y), key[y].pb(i);
}
TwoSet.init(m);
for ( int i = 1, x, y; i <= n; i ++ )
{
x = key[i][0], y = key[i][1];
if ( !dor[i] )
{
TwoSet.addEdge(x,y+m);
TwoSet.addEdge(x+m,y);
}
else
{
TwoSet.addEdge(x,y);
TwoSet.addEdge(x+m,y+m);
}
}
if ( TwoSet.solve() ) puts("YES");
else puts("NO");
return 0;
}
CF_400_D的更多相关文章
随机推荐
- sencha touch 入门系列 (八)sencha touch类系统讲解(下)
接着上一讲,我们通过一组代码来讲解一下st的类的一些属性: Ext.define("MyConfig",{ config:{ website:"http://127.0. ...
- Jboss AS 7 部署web应用程序时无法初始化spring的bean的解决办法
Jboss AS 7 在部署web应用程序的时候无法初始化spring的bean(在tomcat下边不会出现这个问题) 原因是web应用程序没有导入jboss对spring的支持的jar包 解决方法: ...
- nodejs 重定向 (redirect + writeHead(Location))
参考: Node.js实现301.302重定向服务 Express URL跳转(重定向)的实现:res.location()与res.redirect() 一 方式1 index.js var htt ...
- 【BZOJ1269/1507】[AHOI2006]文本编辑器editor Splay
[BZOJ1269][AHOI2006]文本编辑器editor Description 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器.你能帮助他吗?为了明确任务目 ...
- 【BZOJ3772】精神污染 DFS序+主席树
[BZOJ3772]精神污染 Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是 ...
- angular -- ng-ui-route路由及其传递参数?page页面版
前面有说过 ng-ui-route 使用 script 标签来做,但是很多时候,会通过引入模板页面的方式来实现: 具体代码: <!DOCTYPE html> <html lang=& ...
- Javaweb程序打包或exe执行文件
java程序的打包与发布 这里主要是讲解一下怎样将 Java程序打包成独立运行的exe程序包,以下这种方法应该是最佳的解决方案了.NetDuke的EXE程序包了是使用这种方案制作的.在操作步骤上还是比 ...
- apache+tomcat实现session共享
apache+tomcat上篇文章,实现了负载均衡,现在我们实现session共享 一.tomcat集群配置,session 同步配置: tomcat1配置 A.修改Engine节点信息: < ...
- Lucene.net的简单使用
一.Lucene.net的简单介绍 1.为什么要使用Lucene.net 使用like的模糊查询,模糊度太低,中间添加几个字就无法查找.同时会造成数据库的全文检索,效率低下,数据库服务器造 ...
- MacBook鼠标指针乱窜/不受控制问题的解决方法
用了快一年的MacBook Pro最近出现了奇怪的问题.出问题时,鼠标不受控制,屏幕上鼠标指针乱窜,还时不时自动点击,犹如电脑被人远程控制一般.不管是用trackpad还是用外接鼠标,都是同样问题.电 ...