//KM求最优匹配 hdu 3488 Tour
//题意:
//给出两个端点和这两点间的距离,求出这些边构成的所有环中
//边和最小是多少,每个点只能用一次,即每个点只能在一个环中
//思路:
//把每个点拆成两个点,每条边的出度点(起点) 作为x部,入度点(终点) 作为y部
//然后进行最优匹配就是答案了(想知道为什么,画画图想一想就知道了,不知道怎么说)
//因为题目保证有解
//注意:
//1、KM是求最优匹配,求的是最大值,所以边要先加个负号求
//出答案后再加个负号输出就可以了
//2、visy标记的是不需要松弛的点,在hungary中若lx[from] + ly[to] == map[from][to]
//则to点不需要松弛,visy[to]标记为true,若小于的话则需要松弛,
//松弛完就有可能跟x部的点得到上面等式相等的情况,就可能增加一对匹配
#define infile freopen("in.txt", "r", stdin);
#include <stdio.h>
#include <string.h>
#define INF (1<<30)
#define N 205
int n_node, eid;
int map[N][N];
int head[N], lx[N], ly[N], right[N], slack[N];
bool visx[N], visy[N];
bool hungary(int now)
{
visx[now] = true;
for(int i = 1; i <= n_node; ++i)
{
if(map[now][i] != INF)
{
if(visy[i] == true)
continue;
int slck = lx[now] + ly[i] - map[now][i];
if(slck == 0) //不需要松弛,这是匹配的前提
{
visy[i] = true; //不需要松弛的话就标记起来
if(right[i] == 0 || hungary(right[i]))
{
right[i] = now;
return true;
}
}
else
slack[i] = slck < slack[i] ? slck : slack[i];
}
}
return false;
}
void KM()
{
for(int i = 1; i <= n_node; ++i)
{
for(int j = 1; j <= n_node; ++j)
slack[j] = INF;
while(1)
{
for(int j = 1; j <= n_node; ++j)
visx[j] = visy[j] = false;
if(hungary(i))
break;
int min = INF;
for(int j = 1; j <= n_node; ++j)//在需要松弛(visy[j]==false)的点中
if(visy[j] == false && min > slack[j])//找出最小松弛量
min = slack[j];
for(int j = 1; j <= n_node; ++j)
{
if(visx[j] == true)
lx[j] -= min;
if(visy[j] == true)
ly[j] += min;
else
slack[j] -= min;
}
}
}
int ans = 0;
for(int i = 1; i <= n_node; ++i)
ans += map[right[i]][i];
printf("%d\n", -ans);
}
int main()
{
int n_case;
scanf("%d", &n_case);
while(n_case--)
{
int n_edge;
scanf("%d%d", &n_node, &n_edge);
eid = 0;
for(int i = 0; i <= n_node; ++i)
{
lx[i] = -INF;
ly[i] = 0;
right[i] = 0;
for(int j = i; j <= n_node; ++j)
map[i][j] = map[j][i] = -INF;
}
for(int i = 1; i <= n_edge; ++i)
{
int from, to, d;
scanf("%d%d%d", &from, &to, &d);
if(map[from][to] < -d)
{
map[from][to] = -d;
if(lx[from] < -d)
lx[from] = -d;
}
}
KM();
}
return 0;
}