sgu 252 最小费用最大流 题库59

一个有向图。选择最少的路径覆盖所有点。在路径最少的情况下,使得所有路径经过的边的权值之和最小。


const int maxn = 5000 ;
const int maxm = 50000 ;
const int inf = 1000000000 ;
struct Edge{
       int u , v , f , w , next , flow  ;
       Edge(){}
       Edge(int _v , int _f , int _w , int _next):v(_v),f(_f),w(_w),next(_next){}
};
int  g[maxn + 10] ;
Edge e[maxm + 10] ;
int  source , meet ;
int  id ;

void  add(int u , int v  , int f , int w){
      e[++id] = Edge(v , f , w , g[u]) ;
      e[id].u = u ;
      e[id].flow = 0 ;
      g[u] = id ;
      e[++id] = Edge(u , 0 , -w , g[v]) ;
      e[id].u = v ;
      e[id].flow = 0  ;
      g[v] = id ;
}

queue<int> que ;
bool in[maxn + 10] ;
int  dist[maxn + 10] ;
int  pv[maxn + 10] , pe[maxn + 10] ;

int  bfs(){
     while(! que.empty()) que.pop() ;
     que.push(source) ;
     memset(dist , 63 , sizeof(dist)) ;
     dist[source] = 0  ;
     in[source] = 1 ;
     while(! que.empty()){
           int u = que.front() ; que.pop() ;
           in[u] = 0 ;
           for(int i = g[u] ; i ; i = e[i].next){
                int  v = e[i].v ;
                if(e[i].f - e[i].flow > 0 && dist[u] + e[i].w < dist[v]){
                      dist[v] = dist[u] + e[i].w ;
                      pv[v] = u ;
                      pe[v] = i ;
                      if(! in[v]){
                            in[v] = 1 ;  que.push(v) ;
                      }
                }
           }
     }
     return  dist[meet] < inf  ;
}

int  augment(){
     int u = meet  ;
     int delta = inf ;
     while(u != source){
           delta = min(delta , e[pe[u]].f - e[pe[u]].flow) ;
           u = pv[u] ;
     }
     u = meet ;
     while(u != source){
           e[pe[u]].flow += delta ;
           e[pe[u] ^ 1].flow -= delta ;
           u = pv[u] ;
     }
     return dist[meet] * delta ;
}

int  mincostflow(){
     int ans = 0 ;
     while(bfs())  ans += augment() ;
     return ans ;
}

void init(){
     memset(g , 0 , sizeof(g)) ;
     id = 1 ;
}

int  father[maxn] , next[maxn]  ;
vector<int> lis[maxn]  ;

int  main(){
     int i , j  , n , m , u , v , w  , t ;
     init() ;
     cin>>n>>m  ;
     source = 2*n + 1 ;
     meet = 2*n + 2 ;
     for(i = 1 ; i <= n ; i++)  add(source , i , 1 , 0) ;
     for(i = 1 ; i <= n ; i++)  add(i+n  , meet , 1 , 0) ;
     for(i = 1 ; i <= m ; i++){
          scanf("%d%d%d" , &u ,&v ,&w) ;
          add(u , v+n , 1 , w) ;
     }
     w = mincostflow() ;
     t = 0  ;
     memset(father , 0 , sizeof(father)) ;
     memset(next , 0 , sizeof(next)) ;
     for(i = 2 ; i <= id ; i++){
         if(e[i].f == e[i].flow && 1 <= e[i].u && e[i].u <= n && n <= e[i].v && e[i].v <= 2*n){
              father[e[i].v - n] = e[i].u ;
              next[e[i].u] = e[i].v - n  ;
         }
     }
     for(i = 1 ; i <= n ; i++) lis[i].clear() ;
     t = 0 ;
     for(i = 1 ; i <= n ; i++){
          if(father[i] == 0){
              t++ ;
              u = i ;
              while(u){
                   lis[t].push_back(u) ;
                   u = next[u] ;
              }
          }
     }
     printf("%d %d\n" , t , w)  ;
     for(i = 1 ; i <= t ; i++){
          printf("%d" , lis[i].size()) ;
          for(j = 0 ; j < lis[i].size() ; j++) printf(" %d" , lis[i][j]) ;
          printf("\n") ;
     }
     return  0  ;
}




你可能感兴趣的:(sgu 252 最小费用最大流 题库59)