[BZOJ1242][Zju1015 Fishing Net弦图判定][完美消除序列]

50 篇文章 0 订阅
2 篇文章 0 订阅

[BZOJ1242][Zju1015 Fishing Net弦图判定][完美消除序列]

题目大意:

给定一张 N<=1000 个节点, M 条边的无向图,判断该图是否是弦图。

思路:

详细看《弦图与区间图-陈丹琦》:http://wenku.baidu.com/link?url=H7Jlvsd5OfkTMgLhVneYZrkQCBC7IW5ruDjY7m2rPY94nJ1wur6fQfPCcyme2cA7jbE1fEN4Tps2CQXm9sOuW9XC6batJNTEMYw5LXNxheu

但是本蒟蒻还是在这里讲一下思路。。。

概念就不提了,CDQ大神的课件里讲得很详细。。。

首先题目要求判断每个网眼都是三角形,根据弦图的定义图中任意大于等于3的环都至少有一个弦可以显然看出题目就是让我们判断给定的无向图是否是弦图。

然后就是用MCS算法求一下完美消除序列,最后再判断一下完美消除序列是否合法就好了。

一句话概括 MCS 算法:每次寻找没有标号的点中连接已标号的点最多的,标号该点后加入序列。

一句话概括判断序列是否合法:,判断序列中每个元素相邻的所有点 j1,j2,j3,...,jn 中序号最小的点 j1 和其他点 j2,j3,...,jn 是否相邻。

复杂度为: O(n+m)

代码:
#include <bits/stdc++.h>
#define F(x) (x + n + 1)
const int Maxn = 1005;
const int Maxm = 5000005;
using namespace std;
namespace IO {
    inline char get(void) {
        static char buf[1000000], *p1 = buf, *p2 = buf;
        if (p1 == p2) {
            p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
            if (p1 == p2) return EOF;
        }
        return *p1++;
    }
    inline void read(int &x) {
        x = 0; static char c;
        for (; !(c >= '0' && c <= '9'); c = get());
        for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
    }
};
int n, m;
int head[Maxn << 1], sub;
struct Edge {
    int to, nxt;
    Edge(void) {}
    Edge(const int &to, const int &nxt) : to(to), nxt(nxt) {}
} edge[Maxm];
inline int add(int a, int b) {
    edge[++sub] = Edge(b, head[a]), head[a] = sub;
}
int best, f[Maxn], seq[Maxn], rnk[Maxn], tmp[Maxn], t;
int conn[Maxn][Maxn];
bool vis[Maxn];
inline int Max(const int &a, const int &b) {
    return a > b ? a : b;
}
inline void MCS(void) {
    int V;
    for (int i = 1; i <= n; i++)
        add(F(0), i);
    for (int i = n; i; i--) {
        while (1) {
            V = 0;
            for (int p = head[F(best)], v; p && !V; p = edge[p].nxt) {
                v = edge[p].to;
                if (!vis[v]) {
                        V = v;
                    }
                    else head[F(best)] = edge[p].nxt;
                }
            if (V) {
                vis[V] = 1; seq[i] = V;
                for (int p = head[V], v; p; p = edge[p].nxt) {
                    v = edge[p].to;
                    if (!vis[v]) {
                        f[v]++;
                        best = Max(best, f[v]);
                        add(F(f[v]), v);
                    }
                }
                break;
            } else best--;
        }
    }
}
int main(void) {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    IO::read(n), IO::read(m);
    for (int i = 1; i <= m; i++) {
        int a, b;
        IO::read(a), IO::read(b);
        add(a, b), add(b, a);
        conn[a][b] = conn[b][a] = 1;
    }
    MCS();

    for (int i = 1; i <= n; i++) rnk[seq[i]] = i;
    for (int i = n; i; i--) {
        int x = seq[i], mn = 1 << 30, pos; t = 0;
        for (int p = head[x], v; p; p = edge[p].nxt) {
            v = edge[p].to;
            if (rnk[v] > rnk[x]) tmp[++t] = rnk[v];
        }
        for (int p = 1; p <= t; p++)
            if (tmp[p] < mn) mn = tmp[p], pos = p;

        for (int p = 1; p <= t; p++)
            if (p != pos && !conn[seq[tmp[pos]]][seq[tmp[p]]]) return puts("Imperfect"), 0;
    }
    puts("Perfect");
    return 0;
}

完。

By g1n0st

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值