Topic link
title meaning:
a country
towns,
one-way railway. Each railway connects two different towns, and there are no rings in the railway system. Now it is necessary to identify some train running lines that satisfy:
Each railway belongs to at most one train line;
Each town is traversed by at most one train line (by including as a start or end point);
Each town is crossed by at least one train line;
The number of train lines should be as small as possible.
Under the conditions above, the sum of the length of the train running line should be as small as possible.
Ideas:
Years of dissertation topics, place each point
split into points
and out point
,for
This directed edge,
arrive
Connect a directed edge, the weight is the negative value of the length of the path, and then the maximum weight matching of a bipartite graph is obtained, and the negative value of the obtained maximum value is the minimum value of the original path length. Then find the solved path. If a path is the starting point, then it has only the out point, that is to say
If it is the starting point, only
with matching edges
no matching edges, same
If it is the end, only
with matching edges
No, just look for it. Note that there may be only one point.
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<iostream>
typedef long long ll;
const int maxn = 1e2 + 10;
const int INF = 1e9;
using namespace std;
typedef pair<int, int> pa;
vector<pa> G[maxn];
int w[maxn][maxn], n;
int lx[maxn], ly[maxn];
int from[maxn], m;
bool S[maxn], T[maxn];
bool match(int i) {
S[i] = true;
for(int j = 1; j <= n; j++) {
if(lx[i] + ly[j] != w[i][j] || T[j]) continue;
T[j] = true;
if(!from[j] || match(from[j])) {
from[j] = i;
return true;
}
}
return false;
}
void update() {
int a = 1 << 30;
for(int i = 1; i <= n; i++) {
if(!S[i]) continue;
for(int j = 1; j <= n; j++) {
if(T[j]) continue;
a = min(a, lx[i] + ly[j] - w[i][j]);
}
}
for(int i = 1; i <= n; i++) {
if(S[i]) lx[i] -= a;
if(T[i]) ly[i] += a;
}
}
void KM() {
for(int i = 1; i <= n; i++) {
from[i] = lx[i] = ly[i] = 0;
for(int j = 1; j <= n; j++) {
lx[i] = max(lx[i], w[i][j]);
}
}
for(int i = 1; i <= n; i++) {
while(1) {
for(int j = 1; j <= n; j++) S[j] = T[j] = 0;
if(match(i)) break;
else update();
}
}
}
int vis[maxn], to[maxn];
vector<int> vec[maxn];
int main() {
while(scanf("%d %d", &n, &m) != EOF) {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) w[i][j] = -INF;
for(int i = 1; i <= m; i++) {
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
w[u][v] = -c;
}
KM();
int ans = 0, num = 0;
for(int i = 1; i <= n; i++) if(w[from[i]][i] != -INF) ans += w[from[i]][i];
memset(vis, 0, sizeof vis);
memset(to, -1, sizeof to);
for(int i = 0; i < maxn; i++) vec[i].clear();
for(int i = 1; i <= n; i++) {
if(w[from[i]][i] != -INF) {
to[from[i]] = i;
vis[i] = 1;
}
}
for(int i = 1; i <= n; i++) {
if(to[i] == -1 && !vis[i]) { vec[num].push_back(i); num++; continue; }
if(~to[i] && !vis[i]) { ///起始点
int x = i;
while(~x) {
vec[num].push_back(x);
x = to[x];
}
num++;
}
}
printf("%d %d\n", num, -ans);
for(int i = 0; i < num; i++) {
printf("%d", vec[i].size());
for(int j = 0; j < vec[i].size(); j++) printf(" %d", vec[i][j]);
printf("\n");
}
}
return 0;
}