图删边游戏(强连通分量)

图删边游戏
时间限制 : 10000 MS 空间限制 : 65536 KB
单个测试点为1000MS
问题描述

Alice & Bob有一天发现了一株奇怪的灌木、他的枝分叉之后又可以汇合、更奇特的是不仅是同一点的分叉可以汇合、即使分叉点相差很远、两根枝条仍然可以生长到一起(组织连在一块儿了)。

在我们看来他可以抽象为一个无向图。其中有唯一结点是根。
他们认为这是用来玩游戏的绝佳材料。于是他们打算在这棵树上玩伐木游戏,规则如下:
1.两人轮流从灌木上截下枝条(图上的边),每截下一根枝条就将与根不再相连的部分去掉。
2.截去最后一根枝条的人获胜
Alice 先手。
对于给出的无向图输出输出胜利的人的名字。

输入格式

第一行, 一个整数K表示有K组测试数据,对于每组测试数据:
第一行,一个空行
第二行,两个空格间隔的整数N和M,表示图的节点数,M表示无向图中的边数。1号节点为根
第三行,一个空行
接下来M行,每行两个空格间隔的整数X、Y,表示节点X和Y间有边相连

输出格式

一个单词,表示获胜者的名字

样例输入

2

8 7

1 2
1 3
3 4
1 5
5 6
6 7
7 8

扫描二维码关注公众号,回复: 8998417 查看本文章

5 6

1 2
1 3
3 2
1 4
5 1
4 5

样例输出

Alice
Bob

提示

N<=3000,M<=100000

学了删边模型之后也就知道了”偶环”和”奇环”的概念,偶环SG值为0,奇环SG值为1。到这里毫无毛病。。等等
双连通分量是什么鬼啦(゚Д゚≡゚д゚)!?
然后核老板日常甩锅,于是自己查,我认为对于一个图,图里没有桥就算是一个双连通分量了。那这下就好办多了。
同时数据里有坑,居然有重边(MD没有考虑到重边的我才是智障)另外桥就是chiwuajan(tarjan)里dfn[p]

#include <bits/stdc++.h>
using namespace std;
inline int R(){
    char t=getchar();int o=0;bool F=0;
    while(t<48||t>57)F|=t==45,t=getchar();
    for(;t<58&&t>47;t=getchar())o=(o<<1)+(o<<3)+t-48;
    return F?-o:o;
}
inline int Min(int x,int y){
    int m=(x-y)>>31;
    return x&m|y&~m;
}
const int N = 3005;
const int M = 200005;
int Last[N], End[M], Next[M], dfn[N], id[N], low[N], cnt_edge = 1;
int Size[N];
bool bri[M], f[N];
vector<int> v[N];
inline void add_edge( int a, int b ){
    End[++cnt_edge] = b;
    Next[cnt_edge] = Last[a];
    Last[a] = cnt_edge;
}
int T;
int n, m, scc, dfn_clock;
void init(){
    memset(Last,0,sizeof(Last));
    memset(Next,0,sizeof(Next));
    memset(dfn,0,sizeof(dfn));
    memset(bri,0,sizeof(bri));
    memset(id,0,sizeof(id));
    memset(low,0,sizeof(low));
    memset(Size,0,sizeof(Size));
    memset(f,0,sizeof(f));
    n = R(); m = R();
    for( int i = 1; i <= n; i ++ )
        v[i].clear();
    cnt_edge = 1;
    scc = dfn_clock = 0;
    for( int i = 1; i <= m; i ++ ){
        int x = R(), y = R();
        add_edge( x, y );
        add_edge( y, x );
    }
}
void tarjan( int p, int fa ){
    dfn[p] = low[p] = ++dfn_clock;
    int i, y;
    for( i = Last[p], y = End[i]; i; i = Next[i], y = End[i] ){
        if( i == fa ) continue;
        if( dfn[y] )
            low[p] = Min( low[p], dfn[y] );
        else{
            tarjan( y, i^1 );
            low[p] = Min( low[p], low[y] );
            if( dfn[p] < low[y] ) bri[i] = bri[i^1] = 1;
        }
    }
}
void dfs( int p ){
    id[p] = scc; v[scc].push_back( p );
    int i, y;
    for( i = Last[p], y = End[i]; i; i = Next[i], y = End[i] ){
        if( bri[i] ) continue;
        Size[scc] ++;
        if( ! id[y] ) dfs( y );
    }
}
int SG( int p ){
    f[p] = 1;
    int ans = Size[p] >> 1 & 1;
    int tmp = v[p].size();
    for( int x = 0; x < tmp; x ++ )
       for( int i = Last[v[p][x]], y = End[i]; i; i = Next[i], y = End[i] )
           if( ! f[y] ) ans ^= SG( y ) + 1;
    return ans;
}
void solve(){
    tarjan( 1, -1 );
    for( int i = 1; i <= n; i ++ )
        if( ! id[i] ) scc ++, dfs( i );
    for( int i = 2; i <= cnt_edge; i ++ )
        End[i] = id[End[i]];

    puts(SG(id[1])?"Alice":"Bob");
}
int main()
{
    T = R();
    while( T -- ){
        init();
        solve();
    }
    return 0;
}
发布了11 篇原创文章 · 获赞 5 · 访问量 3379

猜你喜欢

转载自blog.csdn.net/qq_24855707/article/details/77927815