Description

In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain one or more loops. (A loop is a route like: A->B->……->P->A.)
Every city should be just in one route.
A loop should have at least two cities. In one route, each city should be visited just once. (The only exception is that the first and the last city should be the same and this city is visited twice.)
The total distance the N roads you have chosen should be minimized.

Input

An integer T in the first line indicates the number of the test cases.
In each test case, the first line contains two integers N and M, indicating the number of the cities and the one-way roads. Then M lines followed, each line has three integers U, V and W (0 < W <= 10000), indicating that there is a road from U to V, with the distance of W.
It is guaranteed that at least one valid arrangement of the tour is existed.
A blank line is followed after each test case.

Output

For each test case, output a line with exactly one integer, which is the minimum total distance.

Sample Input

1
6 9
1 2 5
2 3 5
3 1 10
3 4 12
4 1 8
4 6 11
5 4 7
5 6 9
6 5 4

Sample Output

42

总是1A多没意思啊==虽然我并不知道为啥对

题意:给出有向图,让设计一个或者几个环路使得覆盖所有点,求最小权值和

做法:既然是KM专题的,直接套模板,去重边,取反,1A...

原理:若是选择原图中的某条边就相当于选择二分图中的对应匹配边,因为需要最终所有的点都找到二分图中匹配的点,那么完备匹配最终至少存在一个环!(其他的就意会吧……)

#include <stdio.h>
#include <string.h>
#include<algorithm>
#define M 310
#define inf 0x3f3f3f3f
using namespace std;
int abs(int x)
{
    return x>0?x:-x;
}
int n,m,nx,ny;
int link[M],lx[M],ly[M],slack[M];///lx,ly为顶标,nx,ny分别为x点集y点集的个数
int visx[M],visy[M],w[M][M];

int DFS(int x)
{
    visx[x] = 1;
    for (int y = 1; y <= ny; y ++)
    {
        if (visy[y]) continue;
        int t = lx[x] + ly[y] - w[x][y];
        if (t == 0)
        {
            visy[y] = 1;
            if (link[y] == -1||DFS(link[y]))
            {
                link[y] = x;
                return 1;
            }
        }
        else if (slack[y] > t)  ///不在相等子图中slack 取最小的
            slack[y] = t;
    }
    return 0;
}
int KM()
{
    int i,j;
    memset (link,-1,sizeof(link));
    memset (ly,0,sizeof(ly));
    for (i = 1; i <= nx; i ++)          ///lx初始化为与它关联边中最大的
        for (j = 1,lx[i] = -inf; j <= ny; j ++)
            if (w[i][j] > lx[i])
                lx[i] = w[i][j];

    for (int x = 1; x <= nx; x ++)
    {
        for (i = 1; i <= ny; i ++)
            slack[i] = inf;
        while (1)
        {
            memset (visx,0,sizeof(visx));
            memset (visy,0,sizeof(visy));
            if (DFS(x))     ///若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
                break;  ///若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
            ///方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
            ///所有在增广轨中的Y方点的标号全部加上一个常数d
            int d = inf;
            for (i = 1; i <= ny; i ++)
                if (!visy[i]&&d > slack[i])
                    d = slack[i];
            for (i = 1; i <= nx; i ++)
                if (visx[i])
                    lx[i] -= d;
            for (i = 1; i <= ny; i ++) ///修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
                if (visy[i])
                    ly[i] += d;
                else
                    slack[i] -= d;
        }
    }
    int res = 0;
    for (i = 1; i <= ny; i ++)
        if (link[i] > -1)
            res += w[link[i]][i];
    return res;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    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++)w[i][j]=-inf;
        nx=ny=n;
        while(m--)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            w[x][y]=max(w[x][y],-c);
        }
         printf("%d\n",-KM());
    }
    return 0;
}