题意:在有向图中找若干个环,使得构成这些环的边的权值最小,且满足每个点在这些环中出现且只出现一次,每个环中至少有两个点
难度:2
题解:二分图最优匹配。把每一个点拆成两点Xi和Yi,新增一个附加源s和附加汇t,s向X集合中的所有点连一条容量为1,费用为0的边,Y集合中的所有点向t连一条容量为1,费用为0的边;对于给出的各条边(i,j,w),从Xi向Yj连一条容量不为0,费用为w的边。然后求最小费用最大流,如果最大流为节点数的话,最小费用就是答案,因为对于X[]集合可假设为各点的出度,Y[]集合可以假设为各点的入度,答案能够保证每个点的出度和入度都为1。
难度:2
题解:二分图最优匹配。把每一个点拆成两点Xi和Yi,新增一个附加源s和附加汇t,s向X集合中的所有点连一条容量为1,费用为0的边,Y集合中的所有点向t连一条容量为1,费用为0的边;对于给出的各条边(i,j,w),从Xi向Yj连一条容量不为0,费用为w的边。然后求最小费用最大流,如果最大流为节点数的话,最小费用就是答案,因为对于X[]集合可假设为各点的出度,Y[]集合可以假设为各点的入度,答案能够保证每个点的出度和入度都为1。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf (1<<29)
const int maxn = 1001 , maxm = 44444;
struct Edge {
int u,v,f,c,next;
}edge[maxm];
int E,head[maxn];
void init() {
E=0;memset(head,-1,sizeof(head));
}
void _add(int u,int v,int f,int c) {
edge[E].u=u;edge[E].v=v;edge[E].f=f;edge[E].c=c;edge[E].next=head[u];head[u]=E++;
}
void addedge(int u,int v,int f,int c) {
_add(u,v,f,c); _add(v,u,0,-c);
}
int dist[maxn],p[maxn],sta[maxn];
bool vis[maxn];
int n,maxf,minc;
bool spfa(int s,int t) {
int u,v,f,c;
for(int i=0;i<n;i++) dist[i] = inf , vis[i] = 0 , p[i] = -1;
int top = 0;
sta[++top] = s;
dist[s] = 0;
while(top) {
u = sta[top--];
vis[u] = 0;
for(int i=head[u];i!=-1;i=edge[i].next) {
v=edge[i].v;
f=edge[i].f;
c=edge[i].c;
if(f && dist[v] > dist[u] + c) {
dist[v] = dist[u] + c;
p[v] = i;
if(!vis[v]) {
vis[v] = 1;
sta[++top] = v;
}
}
}
}
return dist[t] != inf;
}
void mcmf(int s,int t) {
maxf = minc = 0;
while(spfa(s,t)) {
//printf("hello,world\n");
int minf = inf;
for(int i=p[t];i!=-1;i=p[edge[i].u])
if(edge[i].f < minf) minf = edge[i].f;
maxf += minf;
minc += minf * dist[t];
for(int i=p[t];i!=-1;i=p[edge[i].u]) {
edge[i].f -= minf;
edge[i^1].f += minf;
}
}
}
int main() {
int N,M;
while(~scanf("%d%d",&N,&M)) {
int s = 0 , t = 2 * N +1;
n = t + 1;
init();
while(M--) {
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u,v+N,1,c);
}
for(int i=1;i<=N;i++) {
addedge(s,i,1,0);
addedge(i+N,t,1,0);
}
mcmf(s,t);
//printf("maxf is %d\n",maxf);
if(maxf==N) printf("%d\n",minc);
else printf("-1\n");
}
return 0;
}