思路:
1.要求每点在k个边不相交环中,则每个点入度与出度相等,且每个点度均为k。
2.拆点。将每点拆为i和i',对于原图中的边i->j,连边i->j',容量为1,费用为边的长度。从源点S到每一点i连边,容量为k,费用为0;从每一点i'向汇点连边,容量为k,费用为0.
3.求最小费用流即为最小花费。
4.若S到i的流量不为k或i'到T的流量不为k,则无解。
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;
const int maxn = 100 + 50;
const int INF = 0x3f3f3f3f;
int S, T;
struct Edge
{
int from, to, cap, flow, cost;
Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
};
struct MM
{
vector<Edge> edges;
vector<int> G[maxn];
vector<int> flag;
int n, m, s, t, cost;
int p[maxn], a[maxn];
int inq[maxn], d[maxn];
void init(int n)
{
this->n = n;
flag.clear();
for (int i = 0; i <= n; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap, int cost)
{
edges.push_back(Edge(from, to, cap, 0, cost));
edges.push_back(Edge(to, from, 0, 0, -cost));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
if (from == S || to == T) flag.push_back(m - 2);
}
bool BF(int s, int t, int& flow, int& cost)
{
for (int i = 0; i <= n; i++) d[i] = INF;
memset(inq, 0, sizeof(inq));
d[s] = 0, inq[s] = 1, p[s] = 0;
queue<int> q;
q.push(s), a[s] = INF;
while (!q.empty())
{
int u = q.front();
q.pop(), inq[u] = 0;
for (int i = 0; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if (e.cap > e.flow&&d[e.to] > d[u] + e.cost)
{
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if (!inq[e.to])
{
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if (d[t] == INF) return false;
flow += a[t];
cost += d[t] * a[t];
for (int u = t; u != s; u = edges[p[u]].from)
{
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
return true;
}
int mcmf(int s, int t, int& cost)
{
this->s = s, this->t = t;
int flow = 0;
cost = 0;
while (BF(s, t, flow, cost));
return flow;
}
};
MM g;
int n, m, k;
int check()
{
for (int i = 0; i < g.flag.size(); i++)
{
Edge& e = g.edges[g.flag[i]];
if (e.flow != k) return 0;
}
return 1;
}
int main()
{
#ifdef debu
freopen("in.txt", "r", stdin);
#endif
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d", &n, &m, &k);
g.init(2 * n + 1);
S = 0, T = 2 * n + 1;
for (int i = 0; i < m; i++)
{
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
u++, v++;
g.addEdge(u, v + n, 1, d);
}
for (int i = 1; i <= n; i++)
{
g.addEdge(S, i, k, 0);
g.addEdge(i + n, T, k, 0);
}
int cost = 0;
int flow = g.mcmf(S, T, cost);
if (!check()) printf("-1\n");
else printf("%d\n", cost);
}
return 0;
}