您的位置:首页 > 编程语言 > Go语言

HDU_1824_Let's go home(2-SAT)

2014-09-12 10:00 387 查看
题型:图论

题意:

中文题,不赘述~

原题戳http://acm.hdu.edu.cn/showproblem.php?pid=1824

分析:

2-SAT解决这样的问题,有一些点,存在敌对关系,如选A就不选B;或者是友好关系,如选A必须选B,求解最后是否能够让所有的点分在两个集合互相对立的集合中。

所谓“2”,指的是,每一个点都有两个属性,即A与~A。

所谓SAT,指的是“可适定的”。

假设选A就不选B,那么有布尔表达式A&~B成立。

假设选A必须选B,那么有布尔表达式A&B成立。

假设有N个点,将每个点分成两个,A和~A。建图时,有友好关系的点建边。

例如:若A与B是友好关系,那么A与 B建边A-> B;

若A与B是敌对关系,那么A与~B建边A->~B。

然后跑一遍Tarjan强连通缩点,如果A与~A在一个环内,那么就无法分成两个集合;否则可以成功分成两个集合。

因此,2-SAT的重点就在于建图,图建好了之后,模板一跑就可以解决了~

对于本题,由于队伍T<=1000,且每个队只有一个队长,所以可以设定1000*2个点。对集训成员重新编号,若队长为A,则两名队员映射为~A。然后根据题意建图,套2-SAT模板即可。

代码:

#include<iostream>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<stack>

#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;

const int M = 2005;

class Twosat {
class Tarjan {
struct E {
int u,v,next;
} e[M*M];
int le,head[M],Index,Bcnt,num[M],belong[M],dfn[M],low[M];
bool instack[M];
stack<int> s;
void tarjan(int u) {
dfn[u]=low[u]=++Index;
instack[u]=true;
s.push(u);
int v;
for(int i=head[u]; ~i; i=e[i].next) {
v=e[i].v;
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);
} else if(instack[v]) {
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]) {
Bcnt++;
do {
v=s.top();
s.pop();
instack[v]=false;
belong[v]=Bcnt;
num[Bcnt]++;
} while(u!=v);
}
}
public:
void init() {
le=Index=Bcnt=0;
mt(head,-1);
mt(num,0);
mt(dfn,0);
mt(low,0);
mt(instack,0);
while(!s.empty()) s.pop();
}
void add(int u,int v) {
e[le].u=u;
e[le].v=v;
e[le].next=head[u];
head[u]=le++;
}
void solve(int n) {
for(int i=1; i<=n; i++) {
if(!dfn[i]) {
tarjan(i);
}
}
}
int getbcnt() {
return Bcnt;
}
int getbelong(int id) {
return belong[id];
}
int getnum(int id) {
return num[id];
}
} T;
class Unitenode {
struct E {
int u,v,next;
} e[M*M];
int n,le,head[M],in[M];
bool mat[M][M];
queue<int> q;
public:
void init(int x) {
n=x;
le=0;
mt(head,-1);
mt(in,0);
mt(mat,0);
for(int i=1; i<=n; i++) mat[i][i]=true;
}
void add(int u,int v) {
if(!mat[u][v]) {
in[v]++;
mat[u][v]=true;
e[le].u=u;
e[le].v=v;
e[le].next=head[u];
head[u]=le++;
}
}
void solve(int tp[]) {
while(!q.empty()) q.pop();
for(int i=1; i<=n; i++) {
if(!in[i]) {
q.push(i);
}
}
int ret=1;
while(!q.empty()) {
int u=q.front();
q.pop();
tp[ret++]=u;
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
in[v]--;
if(!in[v]) {
q.push(v);
}
}
}
}
} U;
void unite() {
U.init(T.getbcnt());
for(int i=1; i<=n; i++) {
for(int j=head[i]; ~j; j=e[j].next) {
U.add(T.getbelong(i),T.getbelong(e[j].v));
}
}
}
struct E {
int u,v,next;
} e[M*M];
int n,le,head[M],tp[M];
bool flag[M];
public:
void init(int x) {
n=x;
T.init();
le=0;
mt(head,-1);
}
void add(int u,int v) {
T.add(u,v);
e[le].u=u;
e[le].v=v;
e[le].next=head[u];
head[u]=le++;
}
bool solve() {
T.solve(n);
for(int i=1,z=n/2; i<=z; i++) {
if(T.getbelong(i)==T.getbelong(i+z))return false;
}
return true;
}
void output(bool ans[]) {
unite();
U.solve(tp);
mt(flag,0);
for(int i=T.getbcnt(); i>0; i--) {
for(int j=1,y; j<=n; j++) {
if(j>n/2)y=j-n/2;
else y=j;
if(!flag[y]&&T.getbelong(j)==tp[i]) {
flag[y]=true;
if(j>n/2) {
ans[j-n/2]=true;
} else {
ans[j]=false;
}
}
}
}
}
} gx;

int num[3010];

int main() {
int t,m;
while(~scanf("%d%d",&t,&m)) {
int a,b,c;
for(int i=1; i<=t; i++) {
scanf("%d%d%d",&a,&b,&c);
num[a] = i;
num[b] = i+t;
num[c] = i+t;
}
gx.init((t+1)*2);
while(m--) {
scanf("%d%d",&a,&b);
a = num[a];
b = num[b];
gx.add(a,b+(b>t?-t:t));
gx.add(b,a+(a>t?-t:t));
}

if(gx.solve()) puts("yes");
else           puts("no");

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: