【ZOJ】1015 Fishing Net

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1015

题意:给出一个n个点的无向图,询问是否为弦图,弦图定义为对于图中任意长度>3的环一定存在环上不相邻的点有边相连(n<=1000)

#include <bits/stdc++.h>
using namespace std;

const int N=1005;
int n, m, ihead[N], cnt, tag[N], pos[N];
bool vis[N];
struct E { int next, to; }e[N*N];
void add(int u, int v) {
	e[++cnt]={ihead[u], v}; ihead[u]=cnt;
	e[++cnt]={ihead[v], u}; ihead[v]=cnt;
}
void cln() {
	memset(ihead, 0, sizeof(int)*(n+1));
	memset(tag, 0, sizeof(int)*(n+1));
	memset(pos, 0, sizeof(int)*(n+1));
	cnt=0;
}
bool check() {
	int x, y, mn, mx;
	for(int now=n; now; --now) {
		mx=-1; mn=~0u>>1; x=y=0;
		for(int i=1; i<=n; ++i) if(!pos[i] && tag[i]>mx) mx=tag[i], x=i;
		pos[x]=now;
		for(int i=ihead[x]; i; i=e[i].next) if(!pos[e[i].to]) tag[e[i].to]++;
		for(int i=ihead[x]; i; i=e[i].next) if(pos[e[i].to]>pos[x] && pos[e[i].to]<mn) mn=pos[e[i].to], y=e[i].to;
		for(int i=ihead[y]; i; i=e[i].next) vis[e[i].to]=1; vis[y]=1;
		for(int i=ihead[x]; i; i=e[i].next) if(pos[e[i].to]>pos[x] && !vis[e[i].to]) return 0;
		for(int i=ihead[y]; i; i=e[i].next) vis[e[i].to]=0; vis[y]=0;
	}
	return 1;
}
int main() {
	while(scanf("%d%d", &n, &m), n&&m) {
		int x, y;
		for(int i=0; i<m; ++i) { scanf("%d%d", &x, &y); add(x, y); }
		check()?puts("Perfect"):puts("Imperfect"); puts("");
		cln();
	}
	return 0;
}

  

弦图判定裸题= =详细看cdq的论文= =《弦图与区间图》

弦图定义上边说了= =

下面来说一下性质:

团:一个完全图,即团中任意点对都有边相连。

单纯点:如果$x$及其相邻的点组成了一个团,那么$x$就是一个单纯点。

完美消除序列:一个点的序列,每个点出现有且一次,且满足对于任意$v_i$,在$v_{i+1} \cdots v_{n}$的诱导子图中$v_i$是一个单纯点。

定理1:一个弦图至少有一个完美消除序列。(证明看论文)

定理2:弦图的诱导子图也是弦图

所以裸的找完美序列的算法就是每一次找不在完美序列的点试着加入当前维护的完美序列中看是否为一个单纯点,如果是则加入。当然这是裸暴力= =

于是cdq论文介绍了两种算法= =一种是字典序bfs..一种是最大势算法,由于我看网上实现都是最大势算法(mcs算法)= =于是我就学下最大势就ok了..反正两种算法复杂度都是$O(n+m)$

首先mcs的原理是先找出一个序列然后判断这是否为一个完美消除序列。那么mcs算法是如何找出一个序列的呢?

鬼知道!反正貌似这就是一种贪心QAQcdq论文也没有解释QAQ,每一次向完美序列前面加一个点,而每次加入的点是与当前维护序列中的点连边最多的不在序列中的点= =这是什么鬼啊!

所以算法就是每一次找与序列中的点连边最多的不在序列中的点,加入= =

最后判断这个序列是否合法:

如果我们要判断$v_i$这个点,即要在$v_{i+1} \cdots v_{n}$找出与$v_i$相邻的点集$v_{j_1}, v_{j_2}, \cdots v_{j_k}$,且是按在序列的顺序从小到大的顺序。那么我们只需要判断$v_{j_1}$与$v_{j_i}, i>1$是否有边相连即可,如果没有,这个图就不是弦图。因为这是按顺序加入到序列中的,我们又要求这个点集是一个团,那么显然我们只需要判断在序列中最前面的$v_{j_1}$与其它是否相连即可,因为$v_{j_i}, i>1$都已经判断过了= =

在找连边最多的点那一步,是能用链表优化到$O(1)$的,但是我太懒了,直接暴力= =反正本题能过...就算不用$O(1)$的,我们也可以用set = =

时间: 2024-12-27 21:35:54

【ZOJ】1015 Fishing Net的相关文章

【ZOJ】3380 Patchouli&#39;s Spell Cards

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3957 题意:m个位置,每个位置填1~n的数,求至少有L个位置的数一样的概率(1<=n,m,l<=100) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct inum { static const int N=205,

【ZOJ】3785 What day is that day? ——浅谈KMP应用之ACM竞赛中的暴力打表找规律

首先声明一下,这里的规律指的是循环,即找到最小循环周期.这么一说大家心里肯定有数了吧,“不就是next数组性质的应用嘛”. 先来看一道题 ZOJ 3785 What day is that day? Time Limit: 2 Seconds      Memory Limit: 65536 KB It's Saturday today, what day is it after 11 + 22 + 33 + ... + NN days? Input There are multiple tes

【ZOJ】3430 Detect the Virus

动态建树MLE.模仿别人的代码模板各种原因wa后,终于AC. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 7 #define MAXN 515*70 8 #define NXTN 256 9 10 bool visit[515]; 11 char str[3005]; 12 unsigned

【BZOJ】1015 星球大战

[解析]排序+并查集 [分析] 求联通块,每操作一次询问一次. 搜索? O(N^2),TLE. 并查集,根据上次的结果更新答案. 问题在于,这是分离的操作,而不是合并的,怎么办呢? 反过来不就是合并的了吗? 给每个点标号,表示它打击的先后次序,例如结点3是第2个打击的,level[3]=2. 对于所有未打击的点,标号为打击的个数nl+1. 然后对于每条边,它一定是在第edge[i].w=min(level[edge[i].u]],level[edge[i].v])次打击不存在的. 根据w值从大到

【有上下界网络流】【ZOJ】2314 Reactor Cooling

[算法]有上下界网络流-无源汇(循环流) [题解] 无源汇网络流相当于重建图后跑最大流. 循环流要求每个点(或边)的流入量和流出量相等. http://www.cnblogs.com/liu-runda/p/6262832.html http://hzwer.com/3356.html 入度>出度时(in[x]>0)时,需要流出去,所以从源向点引一条边,引诱它流出去. 入度<出度时(in[x]<0)时,需要流进来,所以从点向汇引一条边,引诱它流进来. 为何这样正确?源和汇的作用只是

【ZOJ】【3329】One Person Game

概率DP kuangbin总结题目中的第三道 看来还是没有进入状态啊……都说是DP了……当然是要找[状态之间的转移关系]了…… 本题中dp[i]跟 dp[i-(k1+k2+k3)] 到dp[i-1]都有关系……然后所有的dp[i]都跟dp[0]即ans有关…… 用[系数]进行转移……sigh最近越来越水了 1 //BZOJ 1000 2 #include<cmath> 3 #include<vector> 4 #include<cstdio> 5 #include<

【BZOJ】1015: [JSOI2008]星球大战starwar(并查集)

http://www.lydsy.com/JudgeOnline/problem.php?id=1015 看了题解的囧T_T,一开始以为是求割点,但是想到割点不能统计.... 这题用并查集,思想很巧妙. 我们按照逆序建图,也就是从最后一个毁了的星球之后建图.然后从后往前走. 那么怎么统计联通块呢?很简单,我们开个数组记录没有被破坏的星球,然后每一次都将一个星球拿去访问他连接的其他点,看他们是否在一个联通块,如果不是,那么就将连接的那个点加入自己的联通块. #include <cstdio> #

【PAT】1015 德才论 (25)(25 分)

1015 德才论 (25)(25 分) 宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人." 现给出一批考生的德才分数,请根据司马光的理论给出录取排名. 输入格式: 输入第1行给出3个正整数,分别为:N(<=10^5^),即考生总数:L(>=60),为录取最低分数线,即德分和才分均不低于L的考生才有资格被

【ZOJ】Nice Patterns Strike Back(矩阵快速乘法)

dp[[i][j] = sum(dp[i - 1][k]) (k -> j) 状态方程,因为N很大而M很小,所以第一时间可以想到矩阵优化 可能之前没做过类似的题被卡的很厉害. 另外用C++写大数真心麻烦.. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 45; const int maxd = 30005; char n[ma