[BZOJ1997][HNOI2010][2-sat]Planar

[Problem Description]

[Algorithm]
2-sat
[Analysis]
这道题看起来似乎毫无头绪,但仔细想想就能发现其中的奥妙。由于图中有一个哈密顿回路,要想构成平面图就需要先按照这个顺序把点排成一圈。每一条边加进去的时候有两种方法,第一种是从环内连,第二种是从环外连,两种方法选其一。这不就是2-sat问题的模型嘛!而交叉的两条边不能同时出现,根据这个建图然后用o(n)方法判断是否可行即可。这里还有一个问题,由于边数很大,直接做的话会TLE & MLE。但是平面图有一个性质,平面图最多边数为 V * 3 - 6,以此先判断一下再做就不用担心TLE & MLE 了。
[Code]
/**************************************************************
    Problem: 1823
    User: gaotianyu1350
    Language: C++
    Result: Accepted
    Time:40 ms
    Memory:1700 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;
 
#define MAXN 2000
#define MAXM 50000
 
int point[MAXN], next[MAXM], v[MAXM];
int dfsTime[MAXN], lessTime[MAXN], cct[MAXN], st[MAXN];
int nowTime, cntCct, top, tot;
 
int n, m;
 
inline void clear()
{
    memset(point, 0, sizeof(point));
    memset(next, 0, sizeof(next));
    memset(v, 0, sizeof(v));
    memset(dfsTime, 0, sizeof(dfsTime));
    memset(lessTime, 0, sizeof(lessTime));
    memset(cct, 0, sizeof(cct));
    memset(st, 0, sizeof(st));
    nowTime = 0;
    cntCct = 0;
    top = 0;
    tot = 0;
}
 
inline int min(int a, int b)
{
    return a < b ? a : b;
}
 
inline int max(int a, int b)
{
    return a > b ? a : b;
}
 
void tarjan(int now)
{
    lessTime[now] = dfsTime[now] = ++nowTime;
    st[++top] = now;
 
    for (int temp = point[now]; temp; temp = next[temp])
    {
        int tar = v[temp];
        if (!dfsTime[tar])
        {
            tarjan(tar);
            lessTime[now] = min(lessTime[now], lessTime[tar]);
        }
        else
            if (!cct[tar])
                lessTime[now] = min(lessTime[now], dfsTime[tar]);
    }
 
    if (lessTime[now] == dfsTime[now])
    {
        cntCct++;
        while (1)
        {
            cct[st[top--]] = cntCct;
            if (st[top + 1] == now) break;
        }
    }
}
 
inline void addedge(int x, int y)
{
    tot++;
    next[tot] = point[x], point[x] = tot, v[tot] = y;
}
 
inline int part(int x)
{
    return ((x - 1) ^ 1) + 1;
}
 
int main()
{
    //freopen("input.txt", "r", stdin);
    int testcase;
    cin >> testcase;
    while (testcase--)
    {
        scanf("%d%d", &n, &m);
        clear();
        for (int i = 1; i <= m; i++)
        {
            char x1, x2;
            int y1, y2;
            scanf(" %c%d %c%d", &x1, &y1, &x2, &y2);
            int x = y1 * 2 - (x1 == 'm' ? 1 : 0);
            int y = y2 * 2 - (x2 == 'm' ? 1 : 0);
            addedge(part(x), y);
            addedge(part(y), x);
        }
        for (int i = 1; i <= 2 * n; i++)
            if (!dfsTime[i])
                tarjan(i);
        bool isok = true;
        for (int i = 1; i <= n; i++)
            if (cct[i * 2 - 1] == cct[i * 2])
                isok = false;
        if (isok)
            printf("GOOD\n");
        else
            printf("BAD\n");
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值