[hdu-1814] Peaceful Commission题解

来源:互联网 发布:川农在线网络教育平台 编辑:程序博客网 时间:2024/06/07 17:19

题目传送门
题意解析:题目就是给了你n组,每一组有两个人,然后在给你m组关系,关系x,y表示x和y不能在放一起,然后让你在每组中各取出一个人,找出字典序最小的一组方案(原题是任意一组方案,但是hdu上面没有special judge,所以就变成了字典序最小的)。


My opinion:一开始看到的时候毫无头绪,所以除了暴力完全不会。然后想了想,可以发现如果一个人u和另一个人v有矛盾的话,那么如果选了u,那么一定要选和v是同一组的人,这样我们就可以把u和和v是同一组的人连一条边,这样可以排除很多方案数,可以还是会TLE。
直到看到了一篇论文:由对称性解2-sat问题
这题就是样例!!!!

这次直接上代码了:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath> #include<vector>#define rep(i,a,n) for (int i=a;i<=n;i++)#define per(i,a,n) for (int i=a;i>=n;i--)#define Clear(a,x) memset(a,x,sizeof(a))#define ll long long#define INF 2000000000#define eps 1e-8using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}const int maxn=10005;vector<int> G[maxn<<1];bool flag[maxn<<1];int q[maxn<<1];int n,m,top;bool dfs(int u){    if (flag[u^1]) return false;    if (flag[u]) return true;    flag[u]=1;    q[top++]=u;    int len=G[u].size()-1;    rep(i,0,len)        if (!dfs(G[u][i])) return false;    return true;}bool two_sat(){    Clear(flag,0);    for (int i=0;i<n;i+=2)        if (!flag[i]&&!flag[i^1]){            top=0;            if (!dfs(i)){                while (top) flag[q[--top]]=0;                if (!dfs(i^1)) return false;            }        }    return true;}int main(){    while (~scanf("%d%d",&n,&m)){        n*=2;        rep(i,0,n-1) G[i].clear();        while (m--){            int u=read(),v=read();            u--,v--;            G[u].push_back(v^1);            G[v].push_back(u^1);        }        if (two_sat()){            for (int i=0;i<n;i+=2)                if (flag[i]) printf("%d\n",i+1);                    else printf("%d\n",(i^1)+1);        }else puts("NIE");    }    return 0;}

神奇,至少我是这么觉得的。