Conscription
Descriptions
需要征募女兵N人,男兵M人。 每招募一个人需要花费10000美元。 如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱。 给出若干男女之前的1 ~ 9999 之间的亲密度关系, 招募某个人的费用是 10000 - (已经招募了的人中和自己的亲密度的最大值)。 要求通过适当的招募顺序使得招募所有人所花费的费用最小。
Input
输入N, M, R;
接下来输入R行 (x, y, d) 表示第 x 号男兵和第 y 号女兵之间的亲密度是 d
Output
输入最小花费的值。
Sample Input
2
5 5 8
4 3 6831
1 3 4583
0 0 6592
0 1 3063
3 3 4975
1 3 2049
4 2 2104
2 2 7815 5 10
2 4 9820
3 2 6236
3 1 8864
2 4 8326
2 0 5156
2 0 1463
4 1 2439
0 4 4373
3 4 8889
2 4 3133
Sample Output
71071
54223
题目链接
https://vjudge.net/problem/POJ-3723
把人看成点,关系看作边,转化为求解无向图的最大权森林问题,这个问题又可以通过把所有边取反之后用最小生成树的算法求解
典型的kruskal算法
注意要用scanf printf
AC代码
#include#include #include #include #include #include #include #include #include <string> #include #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define
IOS
\
ios_base::
sync_with_stdio(
0);
\
cin.
tie(
0);
#define
Mod
1000000007
#define
eps
1e
-
6
#define
ll
long
long
#define
INF
0x3f3f3f3f
#define
MEM
(x, y)
memset(x, y,
sizeof(x))
#define
Maxn
1000000
+
10
using
namespace
std;
int N, M, R;
int
x[Maxn],
y[Maxn],
d[Maxn];
//男孩 女孩 关系度
struct
edge
{
int u, v, cost;
//u到v的距离为cost
};
bool
cmp(
const edge
&
e1,
const edge
&
e2)
//从小到大排序
{
return
e1.
cost
<
e2.
cost;
}
edge
es[Maxn];
int
par[Maxn];
void
init(
int
n)
//初始化并查集
{
for (
int i
=
0; i
<= n; i
++)
par[i]
= i;
}
int
findr(
int
x)
//寻根
{
if (
par[x]
== x)
return x;
return
par[x]
=
findr(
par[x]);
}
void
unite(
int
x,
int
y)
//合并
{
x
=
findr(x);
y
=
findr(y);
if (x
== y)
return;
par[x]
= y;
}
bool
same(
int
x,
int
y)
//判断根是否相同
{
return
findr(x)
==
findr(y);
}
int
kruskal(
int
V,
int
E)
//kruskal算法求最小生成树
{
sort(es, es
+ E, cmp);
init(V);
int res
=
0;
for (
int i
=
0; i
< E; i
++)
{
edge e
=
es[i];
if (
!
same(
e.
u,
e.
v))
{
unite(
e.
u,
e.
v);
res
+=
e.
cost;
}
}
return res;
}
int
main()
{
int T;
scanf(
"
%d
",
&T);
while (T
--)
//T组测试样例
{
scanf(
"
%d%d%d
",
&N,
&M,
&R);
//存数据
for (
int i
=
0; i
< R; i
++)
scanf(
"
%d%d%d
",
&
x[i],
&
y[i],
&
d[i]);
int V, E;
V
= N
+ M;
//顶点个数
E
= R;
//边个数
for (
int i
=
0; i
< E; i
++)
//存入结构体
{
es[i]
= (edge){
x[i], N
+
y[i],
-
d[i]};
}
printf(
"
%d
\n
",
10000
* (N
+ M)
+
kruskal(V, E));
}
return
0;
}