[BZOJ1242][Zju1015 Fishing Net弦图判定][完美消除序列]
题目大意:
给定一张 N<=1000 个节点, M 条边的无向图,判断该图是否是弦图。
思路:
详细看《弦图与区间图-陈丹琦》:http://wenku.baidu.com/link?url=H7Jlvsd5OfkTMgLhVneYZrkQCBC7IW5ruDjY7m2rPY94nJ1wur6fQfPCcyme2cA7jbE1fEN4Tps2CQXm9sOuW9XC6batJNTEMYw5LXNxheu
但是本蒟蒻还是在这里讲一下思路。。。
概念就不提了,CDQ大神的课件里讲得很详细。。。
首先题目要求判断每个网眼都是三角形,根据弦图的定义图中任意大于等于3的环都至少有一个弦可以显然看出题目就是让我们判断给定的无向图是否是弦图。
然后就是用
一句话概括 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