最小树形图

 

吴文虎的图论算法上写的比较清楚

还有wywcqs博客上也有很详细的解说了

http://hi.baidu.com/wywcgs/blog/item/a1ce10f4a8fa366fdcc47462.html

写了下O(VE)版本的,uva 11183

RankingSubmissionRun TimeLanguageSubmission Date
1059230900.390C++2007-09-17 14:16:18

 

// uva 11183
#include  < cstdio >
#include 
< cstring >
#include 
< cmath >
#include 
< vector >
#include 
< algorithm >
using   namespace  std;

const   int  NMAX  =   1500 ;
const   int  INF  =   0x7f7f7f7f ;
struct  LINKT  {
    
int ls;
    
int adj[NMAX];
    
void clear() {ls = 0;}
    
int operator [] (const int pos) {return adj[pos];}
    
int size() {return ls;}
    
void push_back(const int pos) {adj[ls ++= pos;}
}
;
int  n;
int  path[NMAX][NMAX];
LINKT epath[NMAX], nepath[NMAX];
int  pre[NMAX];
bool  vis[NMAX], del[NMAX];
int  min_cost;
int  fold[NMAX], fpre[NMAX];

void  dfs( int  pos)  {
    
int i;
    vis[pos] 
= true;
    
for(i=0;i<epath[pos].ls;i++{
        
if(!vis[ epath[pos].adj[i] ]) dfs(epath[pos].adj[i]);
    }

}


bool  is_connect( int  root)  {
    
int i;
    memset(vis, 
0sizeof(vis));
    dfs(root);
    
for(i=1;i<=n;i++{
        
if(!vis[i]) return false;
    }

    
return true;
}

// O(VE)
bool  min_tree_graph( int  root)  {
    
int i,j,k;
    
//make sure every node(except root) have in-arc
    if(!is_connect(root)) return false;
    memset(del, 
0sizeof(del));
    min_cost 
= 0;
    
for(i=0;i<=n;i++) fold[i] = fpre[i] = i;
    
while(true{
        
for(i=1;i<=n;i++{
            
if(del[i] || i == root) continue;
            pre[i] 
= i;
            path[i][i] 
= INF;//delete self-cycle
            for(j=0;j<nepath[i].ls;j++{
                
int t = nepath[i].adj[j];
                
if(del[t]) continue;
                
if(path[t][i] < path[ pre[i] ][i]) pre[i] = fpre[fold[i]] = t;
            }

        }
//find min in-arc
        for(i=1;i<=n;i++{
            
if(del[i] || i == root) continue;
            j 
= i;
            memset(vis, 
0sizeof(vis));
            
while(!vis[j] && j != root) {
                vis[j] 
= true;
                j 
= pre[j];
            }

            
if(j == root) continue;//no cycle
            i = j;//cycle begin node
            min_cost += path[ pre[i] ][i];
            
for(j=pre[i]; j != i ;j=pre[j]) {
                del[j] 
= true;//fold cycle
                min_cost += path[ pre[j] ][j];//add cycle cost
            }

            
for(j=0;j<nepath[i].ls;j++{
                
int t = nepath[i].adj[j];
                
if(del[t]) continue;
                path[t][i] 
-= path[ pre[i] ][i];
            }
//i is new fold node
            for(j=pre[i]; j != i ;j=pre[j]) {
                
for(k=0;k<epath[j].ls;k++{
                    
int t = epath[j].adj[k];
                    
if(del[t]) continue;
                    
if(path[i][t] == INF) {
                        epath[i].push_back(t);
                        nepath[t].push_back(i);
                    }

                    path[i][t] 
= min(path[i][t], path[j][t]);
                }

                
for(k=0;k<nepath[j].ls;k++{
                    
int t = nepath[j].adj[k];
                    
if(del[t]) continue;
                    
if(path[t][i] == INF) {
                        epath[t].push_back(i);
                        nepath[i].push_back(t);
                    }

                    
if(path[t][i] > path[t][j] - path[ pre[j] ][j]) {
                        path[t][i] 
= path[t][j] - path[ pre[j] ][j];
                        fold[i] 
= j;//record fold node
                    }

                }

            }
//make new graph
            break;
        }

        
if(i > n) {
            
for(i=1;i<=n;i++{
                
if(del[i] || i == root) continue;
                min_cost 
+= path[ pre[i] ][i];
            }

            
break;
        }
//graph no cycle
    }
//while have cycle
    return true;
}


int  main()  {
    
int i,j,m,t;
    scanf(
"%d"&t);
    
for(i=1;i<=t;i++{
        scanf(
"%d %d"&n,&m);
        memset(path, 
0x7f,sizeof(path));
        
for(j=0;j<=n;j++) epath[j].ls = nepath[j].ls = 0;
        
while(m --{
            
int x,y,z;
            scanf(
"%d %d %d"&x,&y,&z);
            x 
++; y ++;
            
if(x == y) continue;
            
if(path[x][y] == INF) {
                epath[x].push_back(y);
                nepath[y].push_back(x);
            }

            path[x][y] 
= min(path[x][y], z);
        }

        
if!min_tree_graph(1) ) printf("Case #%d: Possums! ", i);
        
else printf("Case #%d: %d ", i,min_cost);
    }

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值