POJ 3723Conscription
来源:互联网 发布:c语言 eof 编辑:程序博客网 时间:2024/05/16 13:38
Windy has a country, and he wants to build an army to protect his country. He has picked up N girls and M boys and wants to collect them to be his soldiers. To collect a soldier without any privilege, he must pay 10000 RMB. There are some relationships between girls and boys and Windy can use these relationships to reduce his cost. If girl x and boy y have a relationship d and one of them has been collected, Windy can collect the other one with 10000-d RMB. Now given all the relationships between girls and boys, your assignment is to find the least amount of money Windy has to pay. Notice that only one relationship can be used when collecting one soldier.
Input
The first line of input is the number of test case.
The first line of each test case contains three integers, N, M and R.
Then R lines followed, each contains three integers xi, yi and di.
There is a blank line before each test case.
1 ≤ N, M ≤ 10000
0 ≤ R ≤ 50,000
0 ≤ xi < N
0 ≤ yi < M
0 < di < 10000
Output
For each test case output the answer in a single line.
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 781
5 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
题意:
就是要找n个女兵,m个男兵,每招一个兵的价钱是10000;然后给出男女兵之间的亲密度。亲密度的作用就是用来省钱,就是要找一个兵时,在已招的兵中,有存在与这个兵有亲密度的,这个兵的价格就为10000-max(亲密度)(就是与已招的兵中最大亲密度);
思路:
这边其实最终是要求最大权值森林,然后这边讲一下为什么可以转化成最大权值森林,以及怎么求解最大权值森林。
1.为什么可以转化成最大权值森林?
首先什么是最大权值森林?这是相对于图来说的,而不是相对于树;首先就得把女兵男兵都看成是一个个的节点,之间的亲密度视为两点之间的权值。这样就构成了图。但是这边的图没有说明一定是连同通的,所以现在就不是一棵树了,而是存在连通分量的森林。到这边其实最后问题的答案就转化称为
ans=(n+m)*10000-最大权和;简要的说就是在这边森林里选边的时候是不能构成回路的,因为若1与2,1与3,2与3之间存在亲密度;你只能计算两个,否则就矛盾了,因为这边是计算的是与已招的兵的亲密度。
2.怎么求解最大权值森林
本来是这个样子的,也就是说最大森林的权值就是把图中所有的权值加起来就是,但是通过上面的分析就是说图中不能存在回路,也就是在一个有n个点的连通分量中,最多只能选n-1条,这边就跟最小生成树及其的像了,区别在于森林有多个连通分量,另外是这边求的是最大值不是最小值;但这边可以转化一下,就是说把亲密度转化为负数,就是求最小权值森林了,ans转化为ans=(n+m)*10000+最小权和(为负数);现在与最小生成树的区别仅在于要求最小生成树的图是连通的,而这边是存在连通分量的,但是用kruskal直接按求值最小生成树的方法来求是没影响的。就是说kruakal算法求解最小权森林也是通用的。
AC代码:
# include <cstdio># include <algorithm> using namespace std;typedef long long int LL;struct edge{//存边 int u;int v;int d;};int father[20010];//存每一个点对应的父亲节点 edge s[50010];//结构体数组 int compare(edge a, edge b){//比较函数 return a.d<b.d;}void init(int n, int m){//初始化并查集 for(int i=0; i<=n+m; i++){father[i]=i;}}int find_root(int n){//查找父亲节点函数 if(father[n]==n){return n;}return father[n]=find_root(father[n]);}int main(){int n, m, r, t, i, j, k, x, y, d, f1, f2;LL sum;edge e;scanf("%d", &t);for(i=1; i<=t; i++){scanf("%d%d%d", &n, &m, &r);for(j=1; j<=r; j++){//输入数据 scanf("%d%d%d", &x, &y, &d);y=y+n;//对y进行转化//女性编号0~n-1, 男性编号n~m-1 s[j].d=-d;s[j].u=x;s[j].v=y;//将d转化为负值 }sum=0;//初始化 sort(s+1, s+1+r, compare);//排序 init(n, m);//初始化并查集 for(j=1; j<=r; j++){//kruskal算法 x=s[j].v;y=s[j].u;d=s[j].d;f1=find_root(x);f2=find_root(y);//查找父亲节点 if(f1!=f2){//不同则合并父亲节点 sum=sum+d;father[f1]=f2;}}printf("%lld\n", (n+m)*(LL)10000+sum);}return 0;}
- poj 3723 Conscription
- POJ 3723 Conscription
- POJ 3723 Conscription
- POJ-3723-Conscription
- POJ 3723 Conscription
- POJ 3723 Conscription MST
- poj 3723 Conscription
- poj 3723 Conscription
- POJ 3723 Conscription
- POJ 3723 Conscription
- poj 3723 Conscription
- POJ--3723 Conscription
- POJ 3723 Conscription
- POJ 3723 Conscription
- POJ 3723Conscription
- POJ 3723 Conscription
- Conscription POJ - 3723
- POJ 3723 Conscription
- Qt 飞机仪表显示
- 流量加速插件 FinalSpeed介绍及一键安装教程
- 最小二乘法曲线拟合
- Volley中listener导致的内存泄露
- POI导出数据库数据到excel
- POJ 3723Conscription
- [php]使用curl扩展post多维数组问题
- 【剑指offer-Java版】22栈的压入弹出序列
- Android studio 导入依赖工程(导入其他工程作为lib)
- 关于调整input里面的输入光标大小
- Eclipse中预设(Androidd)工程的编码格式规范
- Word Flow for iOS输入法正式发布
- iOS 的学习经验
- 【剑指offer-Java版】23从上往下打印二叉树