bzoj 1997 Planar [并查集] [二分图判定] [2-SAT]

1997: [Hnoi2010]Planar

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1509 Solved: 585

Description
这里写图片描述
Input
bzoj 1997 Planar [并查集] [二分图判定] [2-SAT]_第1张图片
Output
这里写图片描述
Sample Input
2
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5

Sample Output
NO
YES

Source
Day1


三种做法,并查集,二分图判定,2-SAT
前两种就是上一道题的check,但是注意要剪枝,m<=3n-6时才有可能成为平面图。


2-SAT解法:

这道题把所有边拆成两个,分别代表在里面和在外面,然后又里面和外面取且一定取一个,那么连上四条边即可。。
又因为这道题只用判断可行性,那么就只用缩点之后判断是否有冲突即可,如果要输出方案,那么就需要按照拓扑序的反序进行点的确定,然后依次标记可选的点,传递不能选的标记,然后该图的染色就是2-SAT问题的解。
另外要注意提前break的时候要保证读完该组数据,不然RE…

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxnode = 205;
const int maxn = 605;
const int maxm = 10005;
struct Edge
{
    int to,next;
}edge[maxn*maxn<<2]; // 4 edges per condition
int head[maxn<<1]; // divided
int maxedge;
inline void addedge(int u,int v)
{
    edge[++maxedge] = (Edge) { v,head[u] };
    head[u] = maxedge;
}
struct Road
{
    int u,v;
}road[maxn],save[maxm];
bool g[maxnode][maxnode];
int a[maxnode],order[maxnode];
int n,m,tmp;
void init()
{
    memset(g,0,sizeof(g));
    memset(head,-1,sizeof(head));
    maxedge = -1;
    m=0;
    for(int i=1;i<=tmp;i++) scanf("%d%d",&save[i].u,&save[i].v);
    for(int i=1;i<=n;i++) scanf("%d",a+i),order[a[i]]=i;
    if(tmp>n*3-6) return; // spacial judge after scanning!!
    for(int i=1;i1]] = g[a[i+1]][a[i]] = true;
    g[a[1]][a[n]] = g[a[n]][a[1]] = true;
    for(int i=1;i<=tmp;i++) if(!g[save[i].u][save[i].v]) road[++m]=save[i];
}
inline bool cross(int i,int j) // cases of including node n,1 is considered another way
{
    int x1=order[road[i].u],y1=order[road[i].v];
    int x2=order[road[j].u],y2=order[road[j].v];
    if(x1>y1) swap(x1,y1);
    if(x2>y2) swap(x2,y2);
    return (x1int dfn[maxn<<1],sccno[maxn<<1];
bool insta[maxn<<1];
int scc_cnt,dfs_clock;
stack <int> sta;
int dfs(int u)
{
    int lowu=dfn[u]=++dfs_clock;
    sta.push(u); insta[u]=true;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            int lowv = dfs(v);
            smin(lowu,lowv);
        }
        else if(insta[v]) smin(lowu,dfn[v]);
    }
    if(lowu>=dfn[u])
    {
        scc_cnt++;
        int t;
        do
        {
            t=sta.top(); sta.pop(); insta[t]=false;
            sccno[t]=scc_cnt; // if needed to print , note the nodes of SCC
        }while(t^u);
    }
    return lowu;
}
void Tarjan()
{
    memset(dfn,0,sizeof(dfn));
    memset(sccno,0,sizeof(sccno));
    dfs_clock = scc_cnt = 0;
    for(int i=1;i<=m;i++)
    {
        if(!dfn[i]) dfs(i);
        if(!dfn[i+m]) dfs(i+m);
    }
}
inline bool check()
{
    for(int i=1;i<=m;i++)
        if(sccno[i] == sccno[i+m]) return false;
    return true;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("planar.in","r",stdin);
    freopen("planar.out","w",stdout);
    #endif
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d%d",&n,&tmp);
        init();
        if(tmp>n*3-6) // judge after scanning all data!!
        {
            printf("NO\n");
            continue;
        }
        for(int i=1;ifor(int j=i+1;j<=m;j++)
                if(cross(i,j))
                {
                    addedge(i,j+m);
                    addedge(j,i+m);
                    addedge(i+m,j);
                    addedge(j+m,i);
                }
        Tarjan();
        if(check()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

你可能感兴趣的:(图论,bzoj,二分图判定,2-SAT,并查集)