//给一个有向图, //找出若干环,使得这些环覆盖全部点且每一个点仅仅能在一个环中 //问所得的全部环的全部边权值之和的最小值为多少 //对于每一个点仅仅有一个入度和一个出度。那么将每一个点拆成 //入度点和出度点,将全部入度点和全部出度点构成一个完备匹配 //因为是完备匹配,所以每一个点的出度和入度都有一个不是自己的点 //相连,那么将完备匹配的全部点连接起来一定是若干环 //所得完备匹配的最小匹配即为答案 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int maxn = 210 ; const int inf = 0x3f3f3f3f ; int lx[maxn] , ly[maxn] , slack[maxn] ; int visx[maxn] , visy[maxn] , match[maxn] ; int map[maxn][maxn] ; int n , m ; int find(int x) { visx[x] = 1 ; for(int i = 1;i <= n;i++) { if(visy[i])continue ; int tmp = lx[x] + ly[i] - map[x][i] ; if(tmp == 0) { visy[i] = 1 ; if(match[i] == -1 || find(match[i])) { match[i] = x ; return true ; } } else slack[i] = min(slack[i] , tmp) ; } return false ; } int KM() { memset(ly , 0 , sizeof(ly)) ; memset(match , -1 , sizeof(match)) ; for(int i = 1;i <= n;i++) { lx[i] = -inf ; for(int j = 1;j <= n;j++) lx[i] = max(lx[i] , map[i][j]) ; } for(int i = 1;i <= n;i++) { for(int j = 1;j <= n;j++) slack[j] = inf ; while(1) { memset(visx , 0 ,sizeof(visx)) ; memset(visy , 0 ,sizeof(visy)) ; if(find(i))break ; int d = inf ; for(int j = 1;j <= n;j++) if(!visy[j]) d = min(d , slack[j]) ; for(int j = 1;j <= n;j++) if(visx[j]) lx[j] -= d ; for(int j = 1;j <= n;j++) if(visy[j]) ly[j] += d ; else slack[j] -=d ; } } int ans = 0 ; for(int i = 1;i <= n;i++) ans += map[match[i]][i] ; return ans ; } int main() { int t ; scanf("%d" , &t) ; while(t--) { scanf("%d%d" , &n , &m) ; for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) map[i][j] = -inf ; while(m--) { int u , v , w ; scanf("%d%d%d" , &u , &v , &w) ; if(u != v && -w > map[u][v]) map[u][v] = -w ; } int ans = KM() ; printf("%d " , -ans) ; } return 0 ; }