题意:一个王国有N个城市,M条路,都是有向的,现在可以去旅游,不过走的路只能是环(至少也需要有两个城市),他们保证这些城市之间的路径都是有环构成的,现在至少需要走多少路。
分析:因为是有向图所以,而且走的是环所以每个城市都会进入一次并且出去一次,构成二分图,并且是完备匹配(完备匹配后肯定都是环了),现在只需要求出来这些匹配的最小值就行,可以把路径的值变为负数,然后求最大匹配值,最后的结果在变成相反数即可,注意路径可能有多条,输入的时候注意取最小的那个
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN = 205;
const int oo = 1e9+7;
int g[MAXN][MAXN], slack[MAXN], N;
int dx[MAXN], dy[MAXN], Ly[MAXN];
bool vx[MAXN], vy[MAXN];
void InIt()
{
memset(Ly, false, sizeof(Ly));
memset(dy, false, sizeof(dy));
for(int i=1; i<=N; i++)
{
dx[i] = -oo;
for(int j=1; j<=N; j++)
g[i][j] = -oo;
}
}
bool Find(int i)
{
vx[i] = true;
for(int j=1; j<=N; j++)
{
if(!vy[j] && dx[i]+dy[j] == g[i][j])
{
vy[j] = true;
if(!Ly[j] || Find(Ly[j]))
{
Ly[j] = i;
return true;
}
}
else if(!vy[j])
slack[j] = min(slack[j], dx[i]+dy[j]-g[i][j]);
}
return false;
}
int KM()
{
int i, j;
for(i=1; i<=N; i++)
{
for(j=1; j<=N; j++)
slack[j] = oo;
while(true)
{
memset(vx, false, sizeof(vx));
memset(vy, false, sizeof(vy));
if( Find(i) == true )break;
int d = oo;
for(j=1; j<=N; j++)
{
if(!vy[j] && d > slack[j])
d = slack[j];
}
for(j=1; j<=N; j++)
{
if(vx[j])dx[j] -= d;
if(vy[j])dy[j] += d;
}
}
}
int sum = 0;
for(i=1; i<=N; i++)
sum += g[Ly[i]][i];
return -sum;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int M, u, v, w;
scanf("%d%d", &N, &M);
InIt();
while(M--)
{
scanf("%d%d%d", &u, &v, &w);
g[u][v] = max(g[u][v], -w);
dx[u] = max(dx[u], g[u][v]);
}
printf("%d\n", KM());
}
return 0;
}