您的位置:首页 > 其它

HDU 1848 2SAT 输出字典序最小

2016-07-30 11:38 381 查看
告诉你两两冲突的序列,让输出字典序最小。

一开始老老实实tarjan,写完了发现后面完全不能好弄,因为选了第一个点,你没办法快速找出全部对立组,只能找出本来在一个pair中的那个对立组,而找不出给定的那个随意的对立组。所以直接从1开始染色,弄不出来就染2。以此类推。

这个题还有一个教训就是,点要多开一倍,边也要多开一倍。老是忘。。。

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<cstdlib>

using namespace std;

const int MAXN=16010;

struct node
{
int v;
int nxt;
};
node edge[40100];//边数
int head[MAXN];
int clo[MAXN];
int dirty[MAXN],dirtop=0;
int n,m;
int cnt=0;
void add_edge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
cnt++;
}
int dfs(int u)
{
clo[u]=1;
clo[u^1]=2;
dirty[dirtop++]=u;
for (int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if (clo[v]==1) continue;
if (clo[v]==2||!dfs(v)) return 0;
}
}
int solve()
{
memset(clo,0,sizeof(clo));
for (int i=0; i<2*n; i+=2)
{
if (!clo[i])
{
dirtop=0;
if (!dfs(i))
{
for (int i=0;i<dirtop;i++) clo[dirty[i]]=clo[dirty[i]^1]=0;
if (!dfs(i+1)) return 0;
}
}
}
return 1;
}

int main()
{
while (scanf ("%d%d",&n,&m)!=EOF)
{
cnt=0;
memset(head,-1,sizeof(head));
while (m--)
{
int t1,t2;
scanf ("%d%d",&t1,&t2);
--t1,--t2;
add_edge(t1,t2^1);
add_edge(t2,t1^1);
}
if (!solve()) printf ("NIE\n");
else
{
for (int i=0;i<2*n;i++)
{
if (clo[i]==1)
{
printf ("%d\n",i+1);
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: