1
http://acm.hdu.edu.cn/showproblem.php?pid=3488
/*
2 一开始看题完全蒙了 ,这怎么用二分图解啊,后来开了别人的结题报告
3 将图中的 入点放到 x集合 出点放到 y集合 看作二分图求解
4 但是还有一个疑问,为什么看成这样求出来的即使答案呢?
5 后来仔细想了想,原来 每个点的入点 出现在x集合 那么起出点 也相应的会出现在 x集合
6 因为每一个点都有至少 一个出点,这样构成的二分图 求其 最小权匹配 即可
7 */
8
9 #include<stdio.h>
10 #define maxn 300
11 #include<string.h>
12 #define inf 0x6ffffff
13 int n,m;
14 int lx[maxn],ly[maxn],visx[maxn],visy[maxn],slack[maxn];
15 int linky[maxn];
16 int w[maxn][maxn];
17 int find(int x)
18 {
19 visx[x]=1;
20 for(int y=1;y<=n;y++)
21 {
22 if(visy[y])continue;
23 int t=lx[x]+ly[y]-w[x][y];
24 if(t==0)
25 {
26 visy[y]=1;
27 if(linky[y]==-1||find(linky[y]))
28 {
29 linky[y]=x;
30 return 1;
31 }
32
33
34 }
35 else
36 if(slack[y]>t)slack[y]=t;
37
38 }
39 return 0;
40
41 }
42 int KM()
43 {
44 int i,j;
45 memset(linky,-1,sizeof(linky));
46 memset(ly,0,sizeof(ly));
47 for(i=1;i<=n;i++)
48 {
49 lx[i]=-inf;//与最大权的不同
50 for(j=1;j<=n;j++)
51 {
52 if(lx[i]<w[i][j])
53 lx[i]=w[i][j];
54 }
55 }
56 for(int x=1;x<=n;x++)
57 {
58 for(i=1;i<=n;i++)
59 slack[i]=inf;
60 while(1)
61 {
62 memset(visx,0,sizeof(visx));
63 memset(visy,0,sizeof(visy));
64 if(find(x))break;
65 int d=inf;
66 for(i=1;i<=n;i++)
67 {
68 if(!visy[i]&&d>slack[i])d=slack[i];
69
70 }
71 for(i=1;i<=n;i++)
72 {
73 if(visx[i])lx[i]-=d;
74 }
75 for(i=1;i<=n;i++)
76 {
77 if(visy[i])ly[i]+=d;
78 else slack[i]-=d;
79 }
80 }
81 }
82 int ans=0;
83 for(i=1;i<=n;i++)
84 {
85 if(linky[i]==-1||w[linky[i]][i]==-inf)return 1;//这里判断是否有完全匹配
86 else
87 ans+=w[linky[i]][i];
88 }
89 return ans;
90 }
91 int main()
92 {
93 int T,i,j,a,b,c;
94 scanf("%d",&T);
95 while(T--)
96 {
97 scanf("%d%d",&n,&m);
98 for(i=0;i<=n;i++)
99 {
100 for(j=0;j<=n;j++)
101 w[i][j]=-inf;
102 }
103 for(i=1;i<=m;i++)
104 {
105 scanf("%d%d%d",&a,&b,&c);
106 if(-c>w[a][b])
107 w[a][b]=-c;//与最大全的不同
108 }
109 printf("%d\n",-KM());
110 }
111 }