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

随机推荐

  1. Elasticsearch配置参数介绍

    Elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml.第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来 ...

  2. Weinre 远程调试移动端手机web页面

    调试场景 1.调试页面在手机上.2.调试工具在PC的chrome3.手机跟pc要在同一个网络环境下,也就是都使用一个wifi 一.安装 Weinre 1.Weinre是基于nodejs实现的,所以使用 ...

  3. maven项目使用SOLR时报 previously initiated loading for a different type with name "javax/servlet/http/HttpServletRequest" 错的解决方法

    环境:Apache solr4.8,maven3,IntellijIDEA 想在项目中使用solr 在pom.xml文件中添加了solr的依赖 solr-core,solrj 和solr-dataim ...

  4. 【BZOJ4149】[AMPPZ2014]Global Warming 单调栈+RMQ+二分

    [BZOJ4149][AMPPZ2014]Global Warming Description 给定一个序列a[1],a[2],...,a[n].请从中选出一段连续子序列,使得该区间最小值唯一.最大值 ...

  5. onethink文章详情如何做上一篇和下一篇!

    其实很简单,如果要做上一篇和下一篇,只要知道当前文章ID的前一个ID和后一个ID即可: //上一篇文章 $prewhere = array(); $prewhere['id'] = array('LT ...

  6. 三维凸包求凸包表面的个数(HDU3662)

    3D Convex Hull Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  7. 单机器启动多个tomcat的配置修改

    首先去apache下载一个tomcat,下载解压版的,比较方便   把这个tomcat(我下载的是tomcat7版本),解压两次,为了方便显示,我把解压出来的tomcat重命名成tomcat71和to ...

  8. R中绘制聚类的离散图

    R中利用cluster简单的绘制常见聚类离散图 # 引入cluster库(clara.fanny) library(cluster) # 聚类散点图绘制 # 引入factoextra,cluster库 ...

  9. Swap---hdu2819(最大匹配)

    题意:通过交换行或者列来实现对角线(左上角到右下角)上都是1, 首先,如果某行全是0或者某列全是0必然不满足情况输出-1,如果能转换的话,那么必然可以通过全由行(列)变换得到: 还有就是对角线上的N个 ...

  10. mysql索引详解(转)

    什么是索引 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的 ...