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