【BZOJ1997】Planar

【题意】

给定一个含哈密顿回路(回路将给出)的图。判断它是不是一个平面图。

【分析】

居然是2-SAT。

由于有一个哈密顿回路,我们先不管其它不在回路上的边,把这幅图围成一个媛。

接下来再考虑其它边。对于其中的任意两条边,如果它们不相交,则必定一个边在圆外,一个边在圆内。

而圆外与圆内是一对相对的状态,又由于状态的选取受其它状态的限制,所以考虑用2-SAT。将每一个不在回路上的边看做两个点i与i'。对于每一对相交的边,连无向边<i,j'>,<j,i'>(因为可以相互影响)。然后缩点判定即可。

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int mn = 205, mm = 10005;
struct edge{
    int a, b;
}e[mm], E[mm];
vector<int > g[mm];
int cir[mn], pos[mn], n, m;
int dfn[mm], low[mm], times;
int stk[mm], scc[mm], cnt, top;
bool instk[mm];
inline void init()
{
    for(int i = 0; i <= m; i++)
        g[i].clear(), dfn[i] = low[i] = stk[i] = scc[i] = 0, instk[i] = 0;
    times = cnt = top = 0;
}
inline int getint()
{
    int ret = 0, flag = 1;
    char c = getchar();
    while(c == ' ' || c == '\n')
        c = getchar();
    if(c == '-')
        flag = -1, c = getchar();
    while(c >= '0' && c <= '9')
        ret = ret * 10 + c - '0', c = getchar();
    return ret * flag;
}
inline void addedge(int a, int b){g[a].push_back(b), g[b].push_back(a);}
void tarjan(int s)
{
    dfn[s] = low[s] = ++times, stk[++top] = s, instk[s] = 1;
    int siz = g[s].size();
    for(int i = 0; i < siz; i++)
    {
        int t = g[s][i];
        if(!dfn[t])
            tarjan(t), low[s] = min(low[s], low[t]);
        else if(instk[t])
            low[s] = min(low[s], dfn[t]);
    }
    if(dfn[s] == low[s])
    {
        ++cnt;
        while(stk[top] != s)
            instk[stk[top]] = 0, scc[stk[top]] = cnt, top--;
        instk[stk[top]] = 0, scc[stk[top]] = cnt, top--;
    }
}
inline bool check()
{
    for(int i = 1; i <= m; i++)
        if(scc[i] == scc[i + m])
            return 0;
    return 1;
}
int main()
{
    int t = getint(), i, j;
    while(t--)
    {
        n = getint(), m = getint();
        for(i = 1; i <= m; i++)
            e[i].a = getint(), e[i].b = getint();
        for(i = 1; i <= n; i++)
            scanf("%d", &cir[i]);
        for(i = 1; i <= n; i++)
            pos[cir[i]] = i;
        if(m > 3 * n - 6)
        {
            puts("NO");
            continue;
        }
        init();
        for(i = 1; i <= m; i++)
        {
            e[i].a = pos[e[i].a], e[i].b = pos[e[i].b];
            if(e[i].a > e[i].b)
                swap(e[i].a, e[i].b);
            if(e[i].b - e[i].a == 1 || e[i].b - e[i].a == n - 1)
                continue;
            E[++top] = e[i];
        }
        m = top, top = 0;
        for(i = 1; i <= m; i++)
            for(j = i + 1; j <= m; j++)
                if((E[i].a < E[j].a && E[j].a < E[i].b && E[i].b < E[j].b) || (E[i].a > E[j].a && E[j].b > E[i].a && E[i].b > E[j].b))
                    addedge(i, j + m), addedge(i + m, j);
        for(i = 1; i <= (m << 1); i++)
            if(!dfn[i])
                tarjan(i);
        puts(check() ? "YES" : "NO");
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值