Conscription
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 15923   Accepted: 5510

Description

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, NM and R.
Then R lines followed, each contains three integers xiyi and di.
There is a blank line before each test case.

1 ≤ NM ≤ 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

解题思路:

表面上看,出题者其实设置了一个看似“二分图”的陷阱,其实这道题真正想考的是最小生成树算法的应用。

利用kruskal算法,将征募士兵的顺序理解成最小生成树算法中添加边的顺序,问题迎刃而解。

参考程序源代码:

#include<stdio.h>
#include<algorithm>
#include<bits/algorithmfwd.h>
#include<iostream>
using namespace std;
const int MAX_E=50005;//最多的边数(关系)
const int MAX_N=20005;//最大的士兵数量
int N,M,R;
struct edge{int u,v,cost;};

bool comp(const edge& e1,const edge& e2)
{
    return e1.cost<e2.cost;
}

edge es[MAX_E];
int V,E;

//下面是自定义好的并查集的实现
int par[MAX_N];//父亲
int rank[MAX_N];//树的高度
void init(int n)
{
    for(int i=0;i<n;i++)
    {
        par[i]=i;
        rank[i]=0;
    }
}

int find(int x)//查询树的根
{
    if(par[x]==x)
    {
        return x;
    }
    else
    {
        return par[x]=find(par[x]);//递归查找
    }
}

void unite(int x,int y)//合并x和y所在的集合
{
    x=find(x);
    y=find(y);
    if(x==y)return;
    if(rank[x]<rank[y])
    {
        par[x]=y;//如果x的高度小于y的高度,则x插到y的下层(减少树的退化)
    }
    else
    {
        par[y]=x;//否则,y插入到x的下层
        if(rank[x]==rank[y])rank[x]++;
    }
}

bool same(int x,int y)
{
    return find(x)==find(y);
}

int kruskal()
{
    sort(es,es+E,comp);//按照边的权值从小到大排序,接下来就可以用贪心思想
    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 x[MAX_E];int y[MAX_E];int d[MAX_E];
void solve()
{
    V=N+M;
    E=R;
    for(int i=0;i<R;i++)
    {
        es[i]=(edge){x[i],N+y[i],-d[i]};//用到了转化的思想,取相反数将最大生成树问题转化为最小生成树问题
    }
    printf("%d\n",10000*(N+M)+kruskal());//输出最少的征募费用
}

int main()
{
    //freopen("C://Users/Administrator/Desktop/in.txt","r",stdin);
    int test;
    scanf("%d",&test);
    while(test--)
    {
        scanf("%d%d%d",&N,&M,&R);
        for(int i=0;i<R;i++)scanf("%d%d%d",&x[i],&y[i],&d[i]);
        solve();
    }
    return 0;
}

POJ 3723 征兵问题(最小生成树算法的应用)的更多相关文章

  1. POJ 3723 Conscription【最小生成树】

    题意: 征用一些男生和女生,每个应都要给10000元,但是如果某个男生和女生之间有关系,则给的钱数为10000减去相应的亲密度,征集一个士兵时一次关系只能使用一次. 分析: kruskal求最小生成树 ...

  2. Prim 最小生成树算法

    Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法.和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm). P ...

  3. Kruskal 最小生成树算法

    对于一个给定的连通的无向图 G = (V, E),希望找到一个无回路的子集 T,T 是 E 的子集,它连接了所有的顶点,且其权值之和为最小. 因为 T 无回路且连接所有的顶点,所以它必然是一棵树,称为 ...

  4. 最小生成树算法(Prim,Kruskal)

    边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...

  5. POJ 2485 Highways【最小生成树最大权——简单模板】

    链接: http://poj.org/problem?id=2485 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...

  6. 最小生成树算法 prim kruskal两种算法实现 HDU-1863 畅通工程

    最小生成树 通俗解释:一个连通图,可将这个连通图删减任意条边,仍然保持连通图的状态并且所有边权值加起来的总和使其达到最小.这就是最小生成树 可以参考下图,便于理解 原来的图: 最小生成树(蓝色线): ...

  7. 笔试算法题(50):简介 - 广度优先 & 深度优先 & 最小生成树算法

    广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能 ...

  8. [算法系列之二十七]Kruskal最小生成树算法

    简单介绍 求最小生成树一共同拥有两种算法,一个是就是本文所说的Kruskal算法,还有一个就是Prime算法. 在具体解说Kruskal最小生成树算法之前,让我们先回想一下什么是最小生成树. 我们有一 ...

  9. 最小生成树算法总结(Kruskal,Prim)

    今天复习最小生成树算法. 最小生成树指的是在一个图中选择n-1条边将所有n个顶点连起来,且n-1条边的权值之和最小.形象一点说就是找出一条路线遍历完所有点,不能形成回路且总路程最短. Kurskal算 ...

随机推荐

  1. java_实现一个类只能声明一个对象

    public class StaticDemo { public int a=10; private static StaticDemo s= new StaticDemo(); private St ...

  2. SqlServer中#和##的区别

    本地临时表的名称以单个数字字符(#)开头,它们仅对当前的用户连接是可见的. 全局临时表的名称以两个数字字符(##)开头,创建后对任何用户都是可见的.

  3. Go语言中的map(十一)

    map是一种无序的基于 key-value 的数据结构,Go语言中的map是引用类型,所以跟切片一样需要初始化才能使用. 定义map 定义 map 的语法如下: map[keyType]ValueTy ...

  4. codeforces 816B Karen and Coffee (差分思想)

    题目链接 816B Karen and Coffee 题目分析 题意:有个人在学泡咖啡,因此看了很多关于泡咖啡温度的书,得到了n种推荐的泡咖啡温度范围[L1,R1] ,此人将有k种做法推荐的温度记为可 ...

  5. python多线程、多进程、协程笔记

    import threading import time import multiprocessing import asyncio movie_list = ['斗破.avi', '复仇者联盟.mp ...

  6. SQL-Serverの自動採番(IDENTITY値)の取得・リセット

    システムに必要なテーブルで.自動的に番号を振っていくものが必要なときがあります. たとえば.各種の伝票データの伝票番号の様なものです. プログラム処理上.データを登録した直後に.自動採番された値を取得 ...

  7. VS2017 VS2019 无法进入安装界面闪退问题(windows7SP1)

    如果离线安装 Visual Studio 2017/2019出现“即将完成…一切即将准备就绪.”的画面后,等几秒安装程序没有任何错误提示就关闭了,无法继续安装. 解决方法: 将vs_enterpris ...

  8. 第96:SVM简介与简单应用

    详细推到见:https://blog.csdn.net/v_july_v/article/details/7624837 python实现方式:

  9. 理解js异步编程

    Promise 背景 javascript语言的一大特点就是单线程,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码,也就是说,同一个时间只能做一件事. 怎么做到异步编程?回调函数.直到no ...

  10. monkey 进阶使用手册,monkey随机测试后怎么定位问题

    首先我们知道使用monkey后,我们可以查看三种类型的日志,一种是安卓内核日志,一种是安卓系统自己的日志,还有一种是monkey日志. 当我们使用monkey进行随机测试时,如何才知道我们这次随机测试 ...