随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

Pku 3140 Contestants Division (无向图割边+树形DP)

由于该图不是一颗树,所以首先要将一些块压缩成点,所谓块就是没有割点的分量,于是只要求出割边,然后删除,之后对整个图进行Floodfill,得到的连通分量再用割边
补图,得到的图一定是一棵树,然后就可以树形DP了。
#include <iostream>
#define MAXN 100010
using namespace std;

struct list {
    list 
*next;
    
int ID;
}
;

int n, m;
int value[ MAXN ];

list data[ 
1000000 ];
list 
*vec[ MAXN ];
list 
*Bri[ MAXN ];
int Ance[ MAXN ];
int Dep[ MAXN ];
int Color[ MAXN ];
int father[ MAXN ];
bool Cut[ MAXN ];
int num[ MAXN ];
#define G 0  // Grey    正在访问
#define B 1  // Black   访问完毕
#define W 2  // White   未曾访问
int root, T;

/*******************求无向图割边割点********************
* list vec[i] 表示原的邻接表                                                                                       * 
* list Bri[i] 保存割边                                                                                                      *
* bool Cut[i] 保存割点                                                                                                    *
* int Ance[i] 保存和i或i的子孙邻接的最高辈分的祖先的深度                            *
* int Dep[i] 保存i点所在的深度                                                                                  *
* int Color[i] 保存当前结点访问情况                                                                     *
* int father[i] 保存i的父亲结点的编号                                                                 *
* int num[i] 缩点后每个点所在的新块的编号                                                  *
********************************************************
*/


int Min ( int a, int b ) {
    
return a < b ? a : b;
}


void BridgeCut( int key, int depth ) {

    
int son = 0;
    Dep[ key ] 
= depth;
    Color[ key ] 
= G;
    Ance[ key ] 
= depth;

    list 
*p, *q;

    
for( p = vec[ key ]->next; p ; p = p->next ) {

        
int next = p->ID;

        
if( next != father[ key ] && Color[ next ] == G) {
            Ance[ key ] 
= Min( Ance[ key ], Dep[ next ] );
        }


        
if( Color[ next ] == W ) {

            father[ next ] 
= key;
            BridgeCut( next, depth 
+ 1);
            son 
++; Ance[ key ] = Min( Ance[ key ], Ance[ next ] );
            
// 判割点
            if( key == root ) {
                
if( son > 1 ) {
                    Cut[ key ] 
= true;
                }

            }
else {
                
if( Ance[ next ] >= Dep[ key ] ) {
                    Cut[ key ] 
= true;
                }

            }


            
// 判割边
            if( Ance[ next ] > Dep[ key ] ) {
                q 
= &data[ T++ ];
                q
->ID = next;
                q
->next = Bri[ key ]->next;
                Bri[ key ]
->next = q;
                
                q 
= &data[ T++ ];
                q
->ID = key;
                q
->next = Bri[ next ]->next;
                Bri[ next ]
->next = q;
            }

        }

    }


    Color[ key ] 
= B;
}



void CreateGraph() {

    
int i, x, y;
    T 
= 0;

    
for(i = 1; i <= n; i++)
        scanf(
"%d"&value[i]);
    
for(i = 1; i <= n; i++{

        Bri[i] 
= &data[ T++ ];
        Bri[i]
->ID = i;
        Bri[i]
->next = NULL;

        vec[i] 
= &data[ T++ ];
        vec[i]
->ID = i;
        vec[i]
->next = NULL;

        Ance[i] 
= INT_MAX;

        Cut[i] 
= false;
        Color[ i ] 
= W;
    }


    list 
*p;
    
while( m-- ) {
        scanf(
"%d %d"&x, &y);

        p 
= &data[ T++ ];
        p
->next = vec[x]->next;
        p
->ID = y;
        vec[x]
->next = p;

        p 
= &data[ T++ ];
        p
->next = vec[y]->next;
        p
->ID = x;
        vec[y]
->next = p;
    }

}


/*
割边割点输出,以及缩块后的图的邻接表
*/


void Print() {
    list 
*p;
    
int i;
    
for(i = 1; i <= n; i++{
        printf(
"%d: ", i);
        
for(p = Bri[i]->next; p; p = p->next) {
            printf(
"%d ", p->ID);
        }

        puts(
"");
    }

    
for(i = 1; i <= n; i++{
        
if( Cut[i] )
            printf(
"point : %d\n", i);
    }

}




/*以下是树形DP的过程*/


bool IsBridge(int u, int v) {
    list 
*p;
    
for( p = Bri[u]->next; p ; p = p->next ) {
        
if( p->ID == v )
            
return 1;
    }

    
return 0;
}


int F;

// 分块 
void dfs( int key ) {
    list 
*p;
    num[ key ] 
= F;
    
for(p = vec[ key ]->next; p ; p = p->next ) {
        
if( Color[ p->ID ] == W  && !IsBridge(key, p->ID) ) {
            Color[ p
->ID ] = B;
            dfs( p
->ID );
        }

    }

}




void FloodFill() {
    
int i;
    
for(i = 1; i <= n; i++)
        Color[i] 
= W;
    F 
= 1;
    
for(i = 1; i <= n; i++{
        
if( Color[i] == W ) {
            Color[i] 
= B;
            dfs(i);
            F 
++;
        }

    }

}


__int64 AllVal[ MAXN ];
__int64 M, zong;
list 
*New[ MAXN ];
int hash[ MAXN ];


// TreeDp
void Search( int key ) {
    list 
*p;
    
int son = 0;

    
for( p = New[ key ]->next; p; p = p->next) {
        
        
int q = p->ID;
        
if( hash[ q ] )
            
continue;
        son 
++;
        hash[ q ] 
= 1;
        Search(q);
        AllVal[ key ] 
+= (__int64)AllVal[ q ];
        __int64 a 
= zong - AllVal[ q ];
        __int64 b 
= AllVal[ q ];
        a 
-= b;
        
if( a < 0)
            a 
= -a;
        
if( a < M )
            M 
= a;
    }
    
}



void TreeDp() {

    
int i;
    M 
= 0;
    memset( AllVal, 
0sizeof(AllVal) );
    
for(i = 1; i <= n; i++{
        AllVal[ num[i] ] 
+= (__int64)value[i];
        M 
+= (__int64)value[i];
    }

    zong 
= M;
    F 
--;
    
for(i = 1; i <= F; i++{
        New[i] 
= &data[ T++ ];
        New[i]
->ID = i;
        New[i]
->next = NULL;
    }


    list 
*p, *q;

    
for(i = 1; i <= n; i++{
        
for(p = Bri[i]->next; p; p = p->next) {
            q 
= &data[ T++ ];
            q
->ID = num[ p->ID ];
            q
->next = New[ num[i] ]->next;
            New[ num[i] ]
->next = q;
        }

    }


    memset( hash, 
0sizeof(hash) );
    hash[
1= 1;
    Search(
1);
}


int main() {

    
int i;
    
int t = 1;

    
while( scanf("%d %d"&n, &m) != EOF && (n || m) ) {
        CreateGraph();
        root 
= 1;
        father[ root ] 
= 0;
        BridgeCut( root, 
0 );
        FloodFill();
        
//Print();
        TreeDp();
        printf(
"Case %d: %I64d\n", t++, M);
    }

    
return 0;
}

posted on 2009-05-07 13:35 英雄哪里出来 阅读(653) 评论(1)  编辑 收藏 引用 所属分类: ACM

评论

# re: Pku 3140 Contestants Division (无向图割边+树形DP)  回复  更多评论   

大牛,orz一下。
2010-03-29 18:00 | 雪舞冰封

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理