题目链接:
http://poj.org/problem?id=3648
题解:
2-SAT问题,不过我用Tarjan + 缩点 + 拓扑排序做的。。。这样可以输出一组可行解,但是我不知道怎么输出字典树最小的解。。比较尴尬。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;
vector <int> mapp[10000];
vector <int> remap[10000];
int dfn[10000],low[10000],stk[10000],vis[10000],color[10000],conflict[10000],col[10000],degree[10000];
int cnt,t,sig;
int n,m,a,b,x1,y1,x2,y2;
char c,d;
void init()
{
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(color,0,sizeof(color));
memset(stk, 0, sizeof(stk));
memset(conflict, 0, sizeof(conflict));
memset(col, 0, sizeof(col));
memset(degree, 0, sizeof(degree));
for(int i=1;i<=2*n;i++)
{
mapp[i].clear();
remap[i].clear();
}
}
void Tarjan(int u)
{
vis[u] = 1;
low[u] = dfn[u] = cnt++;
stk[++t] = u;
for(int i = 0; i < mapp[u].size(); i++)
{
int v = mapp[u][i];
if(!vis[v]) Tarjan(v);
if(vis[v] == 1) low[u] = min(low[u],low[v]);
}
if(dfn[u] == low[u])
{
sig++;
do
{
color[stk[t]] = sig;
vis[stk[t]] = -1;
}
while(stk[t--] != u);
}
}
void rebuild()//反向构图
{
for(int i=1;i <= 2*n;i++)
{
for(int j=0;j< mapp[i].size();j++)
{
int v = mapp[i][j];
if(color[i] != color[v])
{
degree[color[i]]++;
remap[color[v]].push_back(color[i]);
}
}
}
}
void topsort()
{
queue<int> qq;
for(int i = 1 ;i <= sig;i++)
{//现在对缩点后的图进行拓扑
if(!degree[i])
{
qq.push(i);
}
}
while(!qq.empty())
{
int u = qq.front();
qq.pop();
if(!col[u])
{
col[u] = 1;//红色
col[conflict[u]] = 2;//蓝色(因为缩点后变成有向无环图,对应的冲突点只有确定的一个)
}
for(int i=0;i<remap[u].size();i++)
{
int vv = remap[u][i];
degree[vv]--;
if(!degree[vv])qq.push(vv);
}
}
}
int main()
{
while(~scanf("%d %d", &n, &m) && (n+m))
{
init();
for(int i = 1; i <= m; i++)
{
int x,y;
scanf("%d%c %d%c", &x, &c, &y, &d);
if(c == 'h')
{
x1 = 2*x+2;//man
y1 = 2*x+1;//woman
}
else
{
x1 = 2*x+1;//woman
y1 = 2*x+2;//man
}
if(d == 'h')
{
x2 = 2*y+2;//man
y2 = 2*y+1;//woman
}
else
{
x2 = 2*y+1;//woman
y2 = 2*y+2;//man
}
mapp[x1].push_back(y2);
mapp[x2].push_back(y1);
}
mapp[1].push_back(2);
cnt = 1, t = -1, sig = 0;
for(int i = 1; i <= 2 * n; i++)
{
if(!vis[i])
Tarjan(i);
}
// for(int i = 1; i <= 2 * n; i++)
// cout << i << " " <<color[i] <<endl;
bool flag=true;
for(int i = 0; i < n; i++ )
{
if(color[2*i + 1]==color[2*i + 2])
{
flag=false;
break;
}
}
if(flag)
{
for(int i = 1 ; i <= 2*n;i+=2)
{
int aa = color[i],bb = color[i+1];
conflict[aa] = bb;
conflict[bb] = aa;
}
rebuild();
topsort();
//for(int i = 0; i <= 2*n; i++)
// cout << col[i] <<endl;
for(int i=3; i<= 2*n; i+=2)
{
if(i!=3)
printf(" ");
if(col[color[i]] == col[color[1]])
printf("%dw",i/2);
else
printf("%dh",i/2);//否则,取她的老公
}
puts("");
}
else
puts("bad luck");
}
}