找出若干个环覆盖所有的点,使得总的花费最小,因为每个点只能经过一次。
这里源模拟的是出度,汇模拟的是入度,又每个点的出度等于入度等于 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 ;
}