您的位置:首页 > 其它

poj 2942 Knights of the Round Table

2012-08-12 09:31 357 查看
题意:在一张无向图中,问有多少个点不属于任意一个奇圈,孤立点不属于奇圈

首先明确两个定理:

定理1:对于一个点双连通分量,如果找个一个奇圈那么这个分量的其他点也必然在某个奇圈内。

证明很简单,设ab是一个奇圈上的点,c不属于这个奇圈,设c到a和边数为m到b的边数为n,若m+n为奇数,则c位于由这个奇环除ab外的其他边(偶数条)构成一个奇环,如果m+n为偶数,那么c到ab的路径与ab边构成一个奇环。次定理仅适用于点双连通分量,不适用于边连通分量。

1 4
| \ / \
| \ / \
| 2 5 此图在很多时候被用到,尤其是不太确定应该使用边连通还是点连通时。
| / \ /
| / \ /
3 6
依次此题变为判断一个点连通分量里是否存在一个奇圈,有事又用到了定理2
定理2:一个图是二部图当且仅当它不包含奇圈。这是判定二部图的一个方法,并一个方法时染色,因此我们可以染色的方法盘奇圈,如果一个连通分量中某边的两点染色相同则不是二部图,即存在奇圈,则此连通分量中所有点都不会被去除。
另外一种判断二分图的方法是使用并查集,两点有边说明两点不属于一类,每次加边时用差统计量判断是否矛盾即可,效率应该和染色差不多,但是更好写,sgu172 eXam二分图判定
PS:此题很经典也很综合,目前的瓶颈在于想不到那俩定理。。。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;

public class Main{
int maxn = 1010,maxm=2000010;
class node{
int be,ne;
node(int b,int e){
be=b;
ne=e;
}
}
class block{
node buf[]=new node[maxn];
int E[]=new int[maxn],len;
int cut;
void  init(int c)
{
cut=c;
Arrays.fill(E,-1);
len=0;
}
void add(int a,int b)
{
buf[len]=new node(b,E[a]);
E[a]=len++;
}
int color[]=new int[maxn];
void work(){
Arrays.fill(color,-1);
if(tocolor(cut,0))
return;
flag[cut]=1;
for(int i=0;i<len;i++)
flag[buf[i].be]=1;
}
boolean tocolor(int a,int c){
boolean res=true;
color[a] = c;
for (int i=E[a];i!=-1;i=buf[i].ne) {
int b = buf[i].be;
if (color[b] == -1)
res&=tocolor(b, c ^ 1);
if (color[b] == c)
return false;
}
return res;
}
}

node buf[]=new node[maxm];
int E[]=new int[maxn],len;
void add(int a,int b){
buf[len]=new node(b,E[a]);
E[a]=len++;
buf[len]=new node(a,E[b]);
E[b]=len++;
}
void init(){
Arrays.fill(E,-1);
len=0;
}
int map[][] = new int[maxn][maxn], n;
int dfn[] = new int[maxn], low[] = new int[maxn], cnt;
int stack[] = new int[maxn], top;
int flag[] = new int[maxn];
block bk=new block();
void dfs(int a) {
dfn[a] = low[a] = ++cnt;
for (int i=E[a];i!=-1;i=buf[i].ne) {
int b=buf[i].be;
if (dfn[b] == 0) {
stack[++top] = i;
dfs(b);
if (low[b] < low[a])
low[a] = low[b];
if (low[b] >= dfn[a]) {
int x;
bk.init(a);
do {
x = stack[top--];
bk.add(buf[x^1].be, buf[x].be);
} while (buf[x^1].be!=a||buf[x].be!= b);// a组成多个块,不能弹出
bk.work();
}
} else if (dfn[b] < low[a]){
low[a] = dfn[b];
stack[++top] = i;
}
}
}

int solve() {
for (int i = 1; i <= n; i++)
dfn[i] = low[i] = flag[i] = 0;
top = cnt = 0;
for(int i=1;i<=n;i++)
if(dfn[i]==0)
dfs(i);
int ans = 0;
for (int i = 1; i <= n; i++)
if (flag[i] == 0)
ans++;
return ans;
}

StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));

int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}

void run() throws IOException {
while(true){
n = nextInt();
int m = nextInt();
if(n==0)
break;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
map[i][j] = map[j][i] = 1;
int a, b;
while (m-- > 0) {
a = nextInt();
b = nextInt();
map[a][b] = map[b][a] = 0;
}
init();
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
if(map[i][j]==1)
add(i,j);
System.out.println(solve());
}
}

public static void main(String[] args) throws IOException {
new Main().run();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: