UVA 12017 Imitation 【有向图传递闭包的几个结论】【2011上海邀请赛I题】

UVA 12017 Imitation 【有向图传递闭包的几个结论】【2011上海邀请赛I题】

题目大意是给你一个1000个点10000条边的有向图,让你求出与原图等价的传递闭包的最少边和最多边。
解法:
最多边好求,就dfs一下(floyd的邻接表版)算出闭包,统计一下邻接矩阵中1的个数再减去自环即为答案。
最少边稍微复杂一点:
首先图的强联通分量内的边都是必要边,而两两分量之间去掉多重边即可。
关键点是多重边的去除:强联通分量缩点以后,在新图上从每点开始用bfs或者dp做最长路(因为如果某条重复边跨越了某条路径的话,那么对于路径起点来说,路径终点的距离一定不是由这条重复边松弛的),对于每个点,存在几个距离为1的点计数器就加几,然后再加上每个强联通分量之中的边数即可(对于点数大于1的强联通分量,边数=点数)。
纠结,知道怎么捉,不知怎么说,我太弱了。对于纯图论的问题的想法还是太弱了。

附代码:
#include  < iostream >
#include 
< cstdio >
#include 
< cstring >
using   namespace  std;
#include 
< queue >
#define  maxn 1005
#define  maxm 10005
bool  map[maxn][maxn];
int  n,m,tot,newtot;
int  st[maxn];
int  sc[maxn],newst[maxn],pre[maxn],low[maxn],s[maxn],color[maxn];
bool  vis[maxn];
bool  viscolor[maxn],colorvis[maxn];
int  N,cnt0,cnt1;
int  d[maxn];
int  mmm,MMM;
struct  edge
{
    
int  p,next;
    edge(){}
    edge(
int  a, int  b):p(a),next(b){}
}e[maxm],newe[maxm];
void  init()
{
    newtot 
=   0 ;
    tot 
=  cnt0  =  cnt1  =  N  =   0 ;
    fill(newst,newst 
+  n  +   1 , - 1 );
    fill(st,st 
+  n  +   1 , - 1 );
    fill(vis,vis 
+  n  +   1 , 0 );
    fill(color,color 
+  n  +   1 , 0 );
    fill(pre,pre 
+  n  +   1 , - 1 );
    fill(low,low 
+  n  +   1 , - 1 );
    
for ( int  i  =   1 ;i  <=  n;i ++ )
        
for ( int  j  =   1 ;j  <=  n;j ++ )
        {
            
if (i  ==  j)
                map[i][j] 
=   1 ;
            
else
                map[i][j] 
=   0 ;
        }
}
void  add( int  p, int  q)
{
    e[tot] 
=  edge(q,st[p]);
    st[p] 
=  tot ++ ;
}
void  newadd( int  p, int  q)
{
    newe[newtot] 
=  edge(q,newst[p]);
    newst[p] 
=  newtot ++ ;
}
void  dfs( int  u, int  v)
{
    map[u][v] 
=   1 ;
    
for ( int  k  =  st[v]; ~ k;k  =  e[k].next)
        
if (map[u][e[k].p]  ==   0 )
            dfs(u,e[k].p);
}
void  scc( int  now)
{
    
int  v,mm;
    mm 
=  low[now]  =  pre[now]  =  cnt0 ++ ;
    s[N
++ =  now;
    
for ( int  k  =  st[now]; ~ k;k  =  e[k].next)
    {
        
if (pre[e[k].p]  ==   - 1 )
            scc(e[k].p);
        
if (low[e[k].p]  <  mm)
            mm 
=  low[e[k].p];
    }
    
if (mm  <  low[now])
    {
        low[now] 
=  mm;
        
return  ;
    }
    
do
    {
        sc[(v 
=  s[ -- N])]  =  cnt1;
        low[v] 
=  n;
    }
while (s[N]  !=  now);
    cnt1
++ ;
}
void  bfs( int  x)
{
    fill(d,d 
+  cnt1  +   1 , 0 );
    queue 
< int >  Q;
    Q.push(x);
    
while ( ! Q.empty())
    {
        
int  now  =  Q.front();
        Q.pop();
        
for ( int  k  =  newst[now]; ~ k;k  =  newe[k].next)
        {
            
if (d[newe[k].p]  <  d[now]  +   1 )
            {
                d[newe[k].p] 
=  d[now]  +   1 ;
                Q.push(newe[k].p);
            }
        }
    }
    
for ( int  i  =   0 ;i  <  cnt1;i ++ )
        
if (d[i]  ==   1 )
            mmm
++ ;
}
void  gao()
{
    scanf(
" %d %d " , & n, & m);
    init();
    
for ( int  i  =   0 ;i  <  m;i ++ )
    {
        
int  a,b;
        scanf(
" %d %d " , & a, & b);
        add(a,b);
    }
    
for ( int  i  =   1 ;i  <=  n;i ++ )
        dfs(i,i);
    mmm 
=   0 ,MMM  =   0 ;
    
for ( int  i  =   1 ;i  <=  n;i ++ )
        
for ( int  j  =   1 ;j  <=  n;j ++ )
            
if (map[i][j])
                MMM
++ ;
    MMM 
-=  n;
    
for ( int  i  =   1 ;i  <=  n;i ++ )
        
if (pre[i]  ==   - 1 )
            scc(i);
    
for ( int  i  =   1 ;i  <=  n;i ++ )
    {
        color[sc[i]]
++ ;
        
for ( int  k  =  st[i]; ~ k;k  =  e[k].next)
            
if (sc[i]  !=  sc[e[k].p])
                newadd(sc[i],sc[e[k].p]);
    }
    
for ( int  i  =   0 ;i  <  cnt1;i ++ )
        bfs(i);
    
for ( int  i  =   0 ;i  <  n;i ++ )
        
if (color[i]  >   1 )
            mmm 
+=  color[i];
    printf(
" %d %d\n " ,mmm,MMM);
}
int  main()
{
    
int  t;
    scanf(
" %d " , & t);
    
for ( int  i  =   1 ;i  <=  t;i ++ )
    {
        printf(
" Case #%d:  " ,i);
        gao();
    }
}
Down

你可能感兴趣的:(UVA 12017 Imitation 【有向图传递闭包的几个结论】【2011上海邀请赛I题】)