hdu1853 费用流

找出若干个环覆盖所有的点,使得总的花费最小,因为每个点只能经过一次。

这里源模拟的是出度,汇模拟的是入度,又每个点的出度等于入度等于 1 ,那么如果最大流不等于顶点数 n ,则无解,否则答案就是最小费用。

建图:

S->i  费用为0 流量为1

i+n->T同上

若有边u->v

u->v+n 费用为边权,容量为1

const int maxn = 5000 ;
const int maxm = 50000 ;
const int inf = 1000000000 ;
struct Edge{
       int v , f , w , next ;
       int u ;
       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 ;
int  flow ;

void  add(int u , int v  , int f , int w){
      e[++id] = Edge(v , f , w , g[u]) ;
      e[id].u = u ;
      g[u] = id ;
      e[++id] = Edge(u , 0 , -w , g[v]) ;
      e[id].u = v ;
      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 > 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) ;
           u = pv[u] ;
     }
     u = meet ;
     while(u != source){
           e[pe[u]].f -= delta ;
           e[pe[u] ^ 1].f += delta ;
           u = pv[u] ;
     }
     flow += delta ;
     return dist[meet] * delta ;
}

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

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

struct  Task{
        int s , e , val , id ;
        friend bool operator < (const Task A , const Task B){
             return A.s < B.s ;
        }
}tk[1008] ;
int   ans[1008] ;

int   main(){
      int n , m  , i , j , u , v , w  , s ;
      while(cin>>n>>m){
           init() ;
           source = 0  , meet = 2*n + 1 ;
           for(i = 1 ; i <= n ; i++){
                add(source , i , 1 , 0) ;
                add(i+n , meet , 1 , 0) ;
           }
           while(m--){
                 scanf("%d%d%d" , &u , &v , &w) ;
                 add(u , v+n , 1 , w) ;
           }
           flow = 0 ;
           s = mincostflow() ;
           if(flow == n) printf("%d\n" , s) ;
           else          printf("%d\n" , -1) ;
      }
      return 0 ;
}


你可能感兴趣的:(hdu1853 费用流)