2-sat问题的可行解
当我们确定了存在一个可行解的时候,下面的工作往往是要构造一个可行解,那么,如何来构造这样的解呢?
我们知道,当我们选择了一个强连通分量中的一个点的时候,所有的点都会被选择,所以,此时,我们将强连通分量缩点,这样就构造出了一个有向无环图。对这个图进行反向的拓扑排序,然后进行染色就行了。
我们知道,分别含有同一个逻辑变量构造出来的两个点的强连通分量是不可以同时被选择的,使用这个规则染色,再逐个判断即可。
一个问题(poj3648)
John is the only priest in his town. September 1st is the John’s busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year N couples plan to get married on the blessed day. The i-th couple plan to hold their wedding from time Si to time Ti. According to the traditions in the town, there must be a special ceremony on which the couple stand before the priest and accept blessings. The i-th couple need Di minutes to finish this ceremony. Moreover, this ceremony must be either at the beginning or the ending of the wedding (i.e. it must be either from Si to Si + Di, or from Ti - Di to Ti). Could you tell John how to arrange his schedule so that he can present at every special ceremonies of the weddings.
Note that John can not be present at two weddings simultaneously.
这个题也是十分显然的,重要的就是构造可行解,代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 1005
#define MAXM 2005
struct Wedd{
int st;
int en;
int len;
}wedList[MAXN];
struct Edge{
int to;
int next;
}EdgeTable[MAXM*MAXM];
int N;
int head[MAXM];
int dfn[MAXM],low[MAXM],state[MAXM];
int match[MAXM];
int cf[MAXM];
int e,cnt,curT;
stack<int>S;
void Input()
{
int i;
char str1[10],str2[10];
for(i=0;i<N;i++){
scanf("%s %s %d",str1,str2,&wedList[i].len);
wedList[i].st = ((str1[0]-'0')*10+(str1[1]-'0'))*60+((str1[3]-'0')*10+(str1[4]-'0'));
wedList[i].en = ((str2[0]-'0')*10+(str2[1]-'0'))*60+((str2[3]-'0')*10+(str2[4]-'0'));
}
return;
}
void addEdge(int from,int to)
{
EdgeTable[e].to=to;
EdgeTable[e].next=head[from];
head[from]=e++;
}
void print(int num)
{
int a=num/60;
int b=num%60;
char a1=(a/10)+'0',a2=(a%10)+'0';
char b1=(b/10)+'0',b2=(b%10)+'0';
printf("%c%c:%c%c",a1,a2,b1,b2);
return;
}
bool Judge(int a,int aa,int b,int bb)
{
int st1,st2,en1,en2;
if(aa==0){
st1=wedList[a].st;
en1=wedList[a].st+wedList[a].len;
}
else{
st1=wedList[a].en-wedList[a].len;
en1=wedList[a].en;
}
if(bb==0){
st2=wedList[b].st;
en2=wedList[b].st+wedList[b].len;
}
else{
st2=wedList[b].en-wedList[b].len;
en2=wedList[b].en;
}
if(st1>=en2||en1<=st2)return true;
else return false;
}
void get_Graph()
{
memset(head,-1,sizeof(head));
e=0;
int i,j;
for(i=0;i<N;i++){
for(j=i+1;j<N;j++){
if(!Judge(i,0,j,0)){
addEdge(i*2,j*2+1);
addEdge(j*2,i*2+1);
}
if(!Judge(i,1,j,0)){
addEdge(i*2+1,j*2+1);
addEdge(j*2,i*2);
}
if(!Judge(i,1,j,1)){
addEdge(i*2+1,j*2);
addEdge(j*2+1,i*2);
}
if(!Judge(i,0,j,1)){
addEdge(i*2,j*2);
addEdge(j*2+1,i*2+1);
}
}
}
return;
}
void TopSort()
{
queue<int>Q;
int indeg[MAXM];
int vis[MAXM];
vector<int>grid[MAXM];
int i,j;
memset(vis,0,sizeof(vis));
memset(indeg,0,sizeof(indeg));
for(i=0;i<2*N;i++){
for(j=head[i];j!=-1;j=EdgeTable[j].next){
if(match[i]!=match[EdgeTable[j].to]){
indeg[match[i]]++;
grid[match[EdgeTable[j].to]].push_back(match[i]);
}
}
}
for(i=0;i<cnt;i++){
if(!indeg[i]){
indeg[i]=-1;
Q.push(i);
}
}
while(!Q.empty()){
int cur = Q.front();
Q.pop();
if(vis[cur]==0){
vis[cur]=1;
vis[cf[cur]]=-1;
}
for(i=0;i<grid[cur].size();i++){
indeg[grid[cur][i]]--;
if(!indeg[grid[cur][i]])
Q.push(grid[cur][i]);
}
}
for(i=0;i<N;i++){
if(vis[match[2*i]]==1){
print(wedList[i].st);
printf(" ");
print(wedList[i].st+wedList[i].len);
}
else{
print(wedList[i].en-wedList[i].len);
printf(" ");
print(wedList[i].en);
}
printf("\n");
}
for(i=0;i<MAXM;i++)
grid[i].clear();
}
void Dfs(int cur)
{
dfn[cur]=low[cur]=curT++;
state[cur]=1;
S.push(cur);
int i;
for(i=head[cur];i!=-1;i=EdgeTable[i].next){
int dest = EdgeTable[i].to;
if(!state[dest]){
Dfs(dest);
low[cur] = min(low[cur],low[dest]);
}
else if(state[dest]==1)
low[cur] = min(low[cur],low[dest]);
}
if(dfn[cur]==low[cur]){
while(!S.empty()){
int d=S.top();
S.pop();
match[d]=cnt;
state[d]=2;
if(d==cur)break;
}
cnt++;
}
}
void Solve()
{
int i;
memset(state,0,sizeof(state));
memset(cf,-1,sizeof(cf));
memset(match,-1,sizeof(match));
cnt=0;
for(i=0;i<2*N;i++){
if(!state[i]){
curT=0;
Dfs(i);
}
}
for(i=0;i<N;i++){
if(match[2*i]==match[2*i+1]){
printf("NO\n");
return;
}
//mark the tags
//two points from the same logic variable
//can not be chosen at the same time
cf[match[2*i]]=match[2*i+1];
cf[match[2*i+1]]=match[2*i];
}
printf("YES\n");
TopSort();
return;
}
int main()
{
//freopen("input","r",stdin);
while(scanf("%d",&N)!=EOF){
Input();
get_Graph();
Solve();
}
return 0;
}