视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
POJ2723GetLuffyOut(2
2020-11-09 07:21:43 责编:小采
文档


POJ 2723 Get Luffy Out(2-SAT) http://poj.org/problem?id=2723 题意: 你手里有2n把不同的钥匙,这2n把钥匙被分为n对,每对由两个不同的钥匙组成.现在按顺序出现了M个门,每个门上有两个锁,你只需打开其中一个锁就可以打开这个门.现在你需要用你手里的钥匙去按

POJ 2723 Get Luffy Out(2-SAT)

http://poj.org/problem?id=2723

题意:

你手里有2n把不同的钥匙,这2n把钥匙被分为n对,每对由两个不同的钥匙组成.现在按顺序出现了M个门,每个门上有两个锁,你只需打开其中一个锁就可以打开这个门.现在你需要用你手里的钥匙去按顺序打开门,但是对于属于同一组的两把钥匙,如果你用了钥匙A,那么以后永远不能再用钥匙B了.问你按顺序最多能打开多少个门?

分析:

首先有2n把钥匙,所以每个钥匙对应两个节点:用or 不用.

对于同一组的两把钥匙a与b来说: (a=0表示钥匙a选,a=1表示钥匙a不选)

a 用 -> b不用即 a=0 -> b=1

b 用-> a 不用即 b=0 -> a=1

对于一个具有锁(钥匙)a与锁(钥匙)b的门来说,两个锁我们至少要选1个,所以有边: a=1->b=0 和 b=1->a=0.

这样我们通过枚举我们能顺序打开的门数目num,我们令num=5时,添加前5条锁生成的边,看看该2-SAT问题是否有解即可.如果num=5有解,就尝试num=6. 如果num=5误解,那么之后更大的num肯定无解.(注意:这个过程要初始化mark标记数组)

AC代码: (未二分答案,如果用二分,应该能更快)

#include
#include
#include
#include
using namespace std;
const int maxn=2000+100;
struct TwoSAT
{
 int n;
 vector G[maxn*2];
 int S[maxn*2],c;
 bool mark[maxn*2];

 bool dfs(int x)
 {
 if(mark[x^1]) return false;
 if(mark[x]) return true;
 mark[x]=true;
 S[c++]=x;
 for(int i=0;in=n;
 for(int i=0;i<2*n;i++) G[i].clear();
 memset(mark,0,sizeof(mark));
 }

 void add_clause(int x,int xval,int y,int yval)
 {
 x=x*2+xval;
 y=y*2+yval;
 G[x].push_back(y);
 }

 bool solve()
 {
 for(int i=0;i<2*n;i+=2)
 if(!mark[i] && !mark[i+1])
 {
 c=0;
 if(!dfs(i))
 {
 while(c>0) mark[S[--c]]=false;
 if(!dfs(i+1)) return false;
 }
 }
 return true;
 }
}TS;
int main()
{
 int n,m;
 while(scanf("%d%d",&n,&m)==2&&n)
 {
 TS.init(n*2);
 for(int i=0;i 




下载本文
显示全文
专题