BZOJ1823[JSOI2010]满汉全席——2-SAT+tarjan缩点
题目描述
满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中。由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而能够烹饪出经过专家认证的满汉全席,也是中国厨师最大的荣誉之一。 世界满汉全席协会是由能够料理满汉全席的专家厨师们所组成,而他们之间还细分为许多不同等级的厨师。为了招收新进的厨师进入世界满汉全席协会,将于近日举办满汉全席大赛,协会派遣许多会员当作评审员,为的就是要在參赛的厨师之中,找到满汉料理界的明日之星。 大会的规则如下:每位參赛的选手可以得到n 种材料,选手可以自由选择用满式或是汉式料理将材料当成菜肴。大会的评审制度是:共有m 位评审员分别把关。每一位评审员对于满汉全席有各自独特的見解,但基本见解是,要有兩样菜色作为满汉全席的标志。如某评审认为,如果没有汉式东坡肉跟满式的涮羊肉锅,就不能算是满汉全席。但避免过于有主見的审核,大会规定一个评审员除非是在认为必备的两样菜色都没有做出來的狀况下,才能淘汰一位选手,否则不能淘汰一位參赛者。换句话說,只要參赛者能在这兩种材料的做法中,其中一个符合评审的喜好即可通过该评审的审查。如材料有猪肉,羊肉和牛肉时,有四位评审员的喜好如下表: 评审一 评审二 评审三 评审四 满式牛肉 满式猪肉 汉式牛肉 汉式牛肉 汉式猪肉 满式羊肉 汉式猪肉 满式羊肉 如參赛者甲做出满式猪肉,满式羊肉和满式牛肉料理,他将无法满足评审三的要求,无法通过评审。而參赛者乙做出汉式猪肉,满式羊肉和满式牛肉料理,就可以满足所有评审的要求。 但大会后來发现,在这样的制度下如果材料选择跟派出的评审员没有特别安排好的话,所有的參赛者最多只能通过部分评审员的审查而不是全部,所以可能会发生没有人通过考核的情形。如有四个评审员喜好如下表时,则不論參赛者采取什么样的做法,都不可能通过所有评审的考核: 评审一 评审二 评审三 评审四 满式羊肉 满式猪肉 汉式羊肉 汉式羊肉 汉式猪肉 满式羊肉 汉式猪肉 满式猪肉 所以大会希望有人能写一个程序來判断,所选出的m 位评审,会不会发生 没有人能通过考核的窘境,以便协会组织合适的评审团。
输入
第一行包含一个数字 K,代表测试文件包含了K 组资料。每一组测试资料的第一行包含兩个数字n 跟m(n≤100,m≤1000),代表有n 种材料,m 位评审员。为方便起見,材料舍弃中文名称而给予编号,编号分别从1 到n。接下來的m 行,每行都代表对应的评审员所拥有的兩个喜好,每个喜好由一个英文字母跟一个数字代表,如m1 代表这个评审喜欢第1 个材料透过满式料理做出來的菜,而h2 代表这个评审员喜欢第2 个材料透过汉式料理做出來的菜。每个测试文件不会有超过50 组测试资料
输出
每笔测试资料输出一行,如果不会发生没有人能通过考核的窘境,输出GOOD;否则输出BAD(大写字母)。
样例输入
3 4
m3 h1
m1 m2
h1 h3
h3 m2
2 4
h1 m2
m2 m1
h1 h2
m1 h2
样例输出
BAD
这道题有两种建图方式。
第一种是对于每种食材建四个点,分别代表选满、不选满、选汉、不选汉,然后将不选满连向选汉、不选汉连向选满。对于每个评委的条件连两条边,不选第一个就要选第二个,不选第二个就要选第一个。然后$tarjan$缩点,只要每种食材选满和选汉不在同一个强连通分量里就可行。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s[10],t[10];
int dep[500];
int vis[500];
int st[500];
int top;
int tot;
int sum;
int now;
int head[500];
int to[4000];
int next[4000];
int bel[500];
int dfn;
int low[500];
int n,m;
int a,b,c,d;
int T;
void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void tarjan(int x)
{
vis[x]=1;
st[++top]=x;
dep[x]=low[x]=++dfn;
for(int i=head[x];i;i=next[i])
{
if(!dep[to[i]])
{
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
}
else if(vis[to[i]])
{
low[x]=min(low[x],dep[to[i]]);
}
}
if(dep[x]==low[x])
{
sum++;
do
{
now=st[top];
top--;
vis[now]=0;
bel[now]=sum;
}
while(now!=x);
}
}
int find(char *s)
{
int len=strlen(s);
int res=0;
for(int i=1;i<len;i++)
{
res=res*10+s[i]-'0';
}
return res;
}
void solve()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
add(n+i,2*n+i);
add(2*n+i,n+i);
add(3*n+i,i);
add(i,3*n+i);
}
for(int i=1;i<=m;i++)
{
scanf("%s%s",s,t);
a=(s[0]=='h');
b=find(s);
b=(a?2*n+b:b);
c=(t[0]=='h');
d=find(t);
d=(c?2*n+d:d);
add(d+n,b);
add(b+n,d);
}
for(int i=1;i<=4*n;i++)
{
if(!dep[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
if(bel[i]==bel[2*n+i])
{
printf("BAD\n");
return ;
}
}
printf("GOOD\n");
}
void init()
{
tot=dfn=top=sum=0;
memset(head,0,sizeof(head));
memset(bel,0,sizeof(bel));
memset(low,0,sizeof(low));
memset(dep,0,sizeof(dep));
memset(vis,0,sizeof(vis));
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
solve();
}
}
第二种建图方式直接对每种食材建两个点,分别表示选满和选汉。对于每个要求,例如$m1\ h2$,将$h1$连向$h2$,将$m2$连向$m1$。表示第一个不按要求选第二个就要按要求选,第二个不按要求选第一个就要按要求选。同样$tarjan$缩点之后判断每种食材的两个点是否在同一个强连通分量里即可。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s[10],t[10];
int dep[500];
int vis[500];
int st[500];
int top;
int tot;
int sum;
int now;
int head[500];
int to[4000];
int next[4000];
int bel[500];
int dfn;
int low[500];
int n,m;
int a,b,c,d;
int T;
void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void tarjan(int x)
{
vis[x]=1;
st[++top]=x;
dep[x]=low[x]=++dfn;
for(int i=head[x];i;i=next[i])
{
if(!dep[to[i]])
{
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
}
else if(vis[to[i]])
{
low[x]=min(low[x],dep[to[i]]);
}
}
if(dep[x]==low[x])
{
sum++;
do
{
now=st[top];
top--;
vis[now]=0;
bel[now]=sum;
}
while(now!=x);
}
}
int find(char *s)
{
int len=strlen(s);
int res=0;
for(int i=1;i<len;i++)
{
res=res*10+s[i]-'0';
}
return res;
}
void solve()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%s%s",s,t);
a=(s[0]=='h');
b=find(s);
c=(t[0]=='h');
d=find(t);
add((a^1)*n+b,c*n+d);
add((c^1)*n+d,a*n+b);
}
for(int i=1;i<=2*n;i++)
{
if(!dep[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
if(bel[i]==bel[n+i])
{
printf("BAD\n");
return ;
}
}
printf("GOOD\n");
}
void init()
{
tot=dfn=top=sum=0;
memset(head,0,sizeof(head));
memset(bel,0,sizeof(bel));
memset(low,0,sizeof(low));
memset(dep,0,sizeof(dep));
memset(vis,0,sizeof(vis));
memset(next,0,sizeof(next));
memset(to,0,sizeof(to));
memset(st,0,sizeof(st));
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
solve();
}
}
BZOJ1823[JSOI2010]满汉全席——2-SAT+tarjan缩点的更多相关文章
- bzoj1823 [JSOI2010]满汉全席(2-SAT)
1823: [JSOI2010]满汉全席 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1246 Solved: 598[Submit][Status ...
- Bzoj1823 [JSOI2010]满汉全席
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1640 Solved: 798 Description 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的 ...
- BZOJ1823 [JSOI2010]满汉全席 2-sat
原文链接http://www.cnblogs.com/zhouzhendong/p/8125944.html 题目传送门 - BZOJ1823 题意概括 有n道菜,分别可以做成满式和汉式(每道菜只能做 ...
- 洛谷P4171 [JSOI2010] 满汉全席 [2-SAT,Tarjan]
题目传送门 满汉全席 题目描述 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉 ...
- BZOJ1823 [JSOI2010]满汉全席 【2-sat】
题目 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而能够烹饪出经过专家 ...
- bzoj 1823: [JSOI2010]满汉全席【2-SAT+tarjan】
因为每种食材只有一份,所以两个评委的如果有要求同一种食材的两种做法就是不可行,用这个来建立2-SAT模型 然后跑tarjan判可行性即可 #include<iostream> #inclu ...
- [bzoj1823][JSOI2010]满汉全席——2-SAT
题目大意 题目又丑又长我就不贴了,说一下大意,有n种菜,m个评委,每一个评委又有两种喜好,每种菜有满汉两种做法,只能选一种.判断是否存在一种方案使得所有评委至少喜欢一种菜品.输入包含多组数据. 题解 ...
- 【BZOJ1823】[JSOI2010]满汉全席(2-sat)
[BZOJ1823][JSOI2010]满汉全席(2-sat) 题面 BZOJ 洛谷 题解 很明显的\(2-sat\)模板题,还不需要输出方案. 对于任意两组限制之间,检查有无同一种石材要用两种不同的 ...
- 【BZOJ1823】[JSOI2010]满汉全席 2-SAT
[BZOJ1823][JSOI2010]满汉全席 Description 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只 ...
随机推荐
- linux cgroups 简介
cgroups(Control Groups) 是 linux 内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统 ...
- SVM(支持向量机)之Hinge Loss解释
Hinge Loss 解释 SVM 求解使通过建立二次规划原始问题,引入拉格朗日乘子法,然后转换成对偶的形式去求解,这是一种理论非常充实的解法.这里换一种角度来思考,在机器学习领域,一般的做法是经验风 ...
- 如何命名Java变量
如同酒店会给每个房间起个性化的名字一样,程序中的变量也需要用合理的名字进行管理--变量名! 需要注意,给酒店房间起名字时可以是数字,如“802”,也可以是有趣的名字,如“牡丹”.“美国总统”.“水帘洞 ...
- 我们为什么要使用List和Set(List,Set详解)
1.集合概述 类图 集合和数组的区别? 集合基本方法 集合特有的遍历方式? public static void main(String[] args) { //创建集合对象 Collection c ...
- 【转】RCP中org.eclipse.core.runtime.CoreException
org.eclipse.core.runtime.CoreException: Plug-in TRAIN was unable to load class train.Application. 利用 ...
- Linux之磁盘挂载
1.查看磁盘分区情况: fdisk -l 可以看到,红框中的硬盘没有分区. 2.开始分区: fdisk /dev/vdb 3.格式化分区: mkfs.xfs 分区名 4.挂载磁盘 挂载方式1: 手动挂 ...
- Requires: libc.so.6(GLIBC_2.14)(64bit)
centos6 - CentOS 6 - libc.so.6(GLIBC_2.14)(64bit) is needed by - Server Faulthttps://serverfault.com ...
- 使用jmeter来发送json/gzip格式数据 --------笔记
一.使用jmeter来发送gzip数据 有时候我们需要模拟在客户端将数据压缩后, 发送(post)到服务器端. 通常这种情况,会发生在移动终端上. 这样做的好处, 是可以节省流量. 当然, 服务器返 ...
- C#设计模式之7:适配器模式
适配器模式 使用适配器模式的一个重要的点是首先要识别出什么代码(接口)是已经存在的,什么代码(接口)是新的,需要去适配的.适配器的作用是让旧的(现有的)接口能够匹配新的系统(要去适配的). 比如有下面 ...
- "errcode":40163,"errmsg":"code been used...报错,做PC微信登录时出现code been used...报错问题
这是一个坑,一个巨坑,一个恶心的坑 出现这个问题的大概意思就是微信回调了两次登录接口,code使用了两次,而在微信官方文档上写着code只能用一次,用来获取access_token,但我TM看着就糊涂 ...