您的位置:首页 > 其它

NOIP模拟题 通讯 强连通分量缩点 最小树形图--朱刘算法

2017-09-02 15:54 393 查看
通讯

(message.cpp\c\pas)

【问题描述】

“这一切都是命运石之门的选择。”

试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短信,并由此得知了伦太郎制作出了电话微波炉(仮)。

为了掌握时间机器的技术,SERN总部必须尽快将这个消息通过地下秘密通讯网络,传达到所有分部。

SERN共有N个部门(总部编号为0),通讯网络有M条单向通讯线路,每条线路有一个固定的通讯花费Ci。

为了保密,消息的传递只能按照固定的方式进行:从一个已知消息的部门向另一个与它有线路的部门传递(可能存在多条通信线路)。我们定义总费用为所有部门传递消息的费用和。

幸运的是,如果两个部门可以直接或间接地相互传递消息(即能按照上述方法将信息由X传递到Y,同时能由Y传递到X),我们就可以忽略它们之间的花费。

由于资金问题(预算都花在粒子对撞机上了),SERN总部的工程师希望知道,达到目标的最小花费是多少。

【输入格式】

多组数据,文件以2个0结尾。

每组数据第一行,一个整数N,表示有N个包括总部的部门(从0开始编号)。然后是一个整数M,表示有M条单向通讯线路。

接下来M行,每行三个整数,Xi,Yi,Ci,表示第i条线路从Xi连向Yi,花费为Ci。

【输出格式】

每组数据一行,一个整数表示达到目标的最小花费。

【输入输出样例】

message.in

3 3

0 1 100

1 2 50

0 2 100

3 3

0 1 100

1 2 50

2 1 100

2 2

0 1 50

0 1 100

0 0

message.out

150

100

50

【样例解释】

第一组数据:总部把消息传给分部1,分部1再传给分部2.总费用:100+50=150.

第二组数据:总部把消息传给分部1,由于分部1和分部2可以互相传递消息,所以分部1可以无费用把消息传给2.总费用:100+0=100.

第三组数据:总部把消息传给分部1,最小费用为50.总费用:50.

【数据范围】

对于10%的数据,保证M=N-1

对于另30%的数据,N ≤ 20 ,M ≤ 20

对于100%的数据,N ≤ 50000 ,M ≤ 10^5 ,Ci ≤ 10^5 ,数据组数 ≤ 5

数据保证一定可以将信息传递到所有部门。

讲道理,觉得题目性质太明显了,直接做就好了,可是这样太没意思了

于是就写了朱刘算法

# include <cctype>
# include <cstdio>
# include <cstring>

char buf [1 << 24], *ss, *tt ;

inline char pick ( )  {
if ( ss == tt )  {
tt = buf + fread ( ss = buf, 1, 1 << 24, stdin ) ;
if ( ss == tt ) return -1 ;
}
return *ss ++ ;
}

inline int read ( )  {
register int x ;
register char c ;
while ( ! isdigit ( c = pick ( ) ) ) ;
for ( x = -48 + c ; isdigit ( c = pick ( ) ) && ( c != -1 ) ; x= x * 10 + c - 48 ) ;
return x ;
}

const int N = 50005 ;

int in
, id
, pre
, vis
;

struct Edge  {
int u, v, c ;
} e [N << 1] ;

int qcnt ;

inline int Zhuliu_algorithm ( int root, int n, int m, Edge* g )  {
int rt ( 0 ) ;
register int i, u, v ;
for ( ; ; )  {
memset ( in, 0x3f, sizeof ( int ) * ( n + 1 ) ) ;
for ( i = 1 ; i <= m ; ++ i )  {
u = g [i].u, v = g [i].v ;
if ( g [i].c < in [v] && ( u ^ v ) )  {
in [v] = g [i].c ;
pre [v] = u ;
}
}
for ( i = 1 ; i <= n ; ++ i )  {
if ( i == root )    continue ;
if ( in [i] == 0x3f3f3f3f ) return -1 ;
}
int cnt ( 0 ) ;
memset ( id, -1, sizeof ( int ) * ( n + 1 ) ) ;
memset ( vis, -1, sizeof ( int ) * ( n + 1 ) ) ;
in [root] = 0 ;
for ( i = 1 ; i <= n ; ++ i )  {
rt += in [i] ;
int v = i ;
while ( vis [v] != i && id [v] == -1 && v != root )  {
vis [v] = i ;
v = pre [v] ;
}
if ( v != root && id [v] == -1 )  {
for ( u = pre [v] ; u != v; u = pre [u] )
id [u] = cnt ;
id [v] = ++ cnt ;
}
}
if ( cnt == 0 ) return rt ;  //break ;
for ( i = 1 ; i <= n ; ++ i )   if ( id [i] == -1 ) id [i] = ++ cnt ;
for ( i = 1 ; i <= m ; ++ i )  {
v = g [i].v ;
g [i].v = id [g [i].v] ;
g [i].u = id [g [i].u] ;
if ( g [i].u ^ g [i].v )  {
g [i].c -= in [v] ;
}
}
n = cnt ;
root = id [root] ;
}
//  return rt ;
}

struct edge  {
int to, nxt, w ;
} g [N << 1] ;

int ecnt, head
;

int stk
, top ;
int dfn
, low
, place
, scnt, idx ;

inline void Dfs ( int u )  {
dfn [u] = low [u] = ++ idx ;
stk [++ top] = u ;
for ( register int i = head [u] ; i ; i = g [i].nxt )  {
int v = g [i].to ;
if ( ! dfn [v] )  {
Dfs ( v ) ;
if ( low [v] < low [u] )    low [u] = low [v] ;
} else if ( ! place [v] && dfn [v] < low [u] )  low [u] = dfn [v] ;
}
if ( low [u] == dfn [u] )  {
int tp = u, cur ;
++ scnt ;
do  {
cur = stk [top --] ;
place [cur] = scnt ;
} while ( tp ^ cur ) ;
}
}

int main ( )  {
freopen ( "message.in", "r", stdin ) ;
freopen ( "message.out", "w", stdout ) ;
int n ;
register int i, u, v, w, m ;
for ( ; ; )  {
n = read ( ), m = read ( ) ;
if ( n == 0 && m == 0 ) return 0 ;
if ( m == n - 1 )  {
int ans ( 0 ) ;
while ( m -- )  {
u = read ( ), v = read ( ), w = read ( ) ;
ans += w ;
}
printf ( "%d\n", ans ) ;
continue ;
}
ecnt = 0 ;
memset ( dfn, 0, sizeof ( int ) * n ) ;
memset ( low, 0, sizeof ( int ) * n ) ;
memset ( head, 0, sizeof ( int ) * n ) ;
memset ( place, 0, sizeof ( int ) * n ) ;
while ( m -- )  {
u = read ( ), v = read ( ), w = read ( ) ;
g [++ ecnt] = ( edge ) {  v, head [u], w  }, head [u] = ecnt ;
}
scnt = 0 ;
idx = 0 ;
Dfs ( 0 ) ;
qcnt = 0 ;
for ( u = 0 ; u < n ; ++ u )
for ( i = head [u] ; i ; i = g [i].nxt )  {
v = g [i].to ;
if ( place [u] ^ place [v] )  {
e [++ qcnt] = ( Edge ) {  place [u], place [v], g [i].w } ;
}
}
printf ( "%d\n", Zhuliu_algorithm ( *place, scnt, qcnt, e ) ) ;
}
}


理论复杂度会T,还是踩标程,没办法(微笑)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: