POJ 3723 -- Conscription


http://poj.org/problem?id=3723
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
1

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
Sample Output
71071
题意:需要招募女兵N人,男兵M人。每征募一人需要$10000。但是如果两个人之间(已征募与要被征募)有关系,就可以依据亲密度大小减免花费,此时花费等于10000-已经征募的人中与ta的最大亲密度。求花费最少的招募顺序。
题解:是一个无向图,并且可以得知这是一个森林,所以可以把人看做点,关系是边权,就转换为求最大权森林。将边权取反,采用kruskal(因为可能有圈)。
http://tech.artyoo.me/?p=60
男生女生是图中相同类型的点,只不过只有男生和女生之间才有路连通。所以用krusical来做,每次取最小值加入。和最小生成树一模一样

最后解答的那个序列,对应了原图各个连通分量上所有的生成树(若原图本身是一个连通图,那么解答序列对应了该连通图的一颗生成树)。但无论如何,最后在原图各个连通分量上生成的,必定是一颗树,而不含有圈。若有圈,则会产生矛盾。原图的边的权重,代表了男女之间的亲密度,其实也代表了招募该对男女可以减少的费用:原本招募一男一女需要10000*2=20000RMB,而若他们之间的亲密度为d,则在先招募其中一人后,再招募其中另一人则可减少d的费用,因此招募此二人的总费用实际为(10000*2-d)RMB。因此,此题实则可以转化为:在原图上找最大生成森林(若原图为连通图,则为找原图的最大生成树),这最大生成森林(或最大生成树)的总权值,其实代表了可以减少的费用,计为P;则最后的最小总费用就是10000*(N+M)-P。求最大生成森林,自然可以转换为求最小生成森林(树),其技巧是将所有边上的权值取负,则最后对应的最小生成森林(树)的总权值P'就是P的相反数,此时最后的最小总费用就是10000*(N+M)+P'。
int par[maxn];//并查集父亲
 22 int hrank[maxn];//并查集树的高度
 23 int x[maxn],y[maxn],d[maxn];
 24 struct edge{
 25     int u,v,cost;
 26 };
 27 edge es[maxn];
 28 int V,E;
 29 void init(int n)
 30 {
 31     for (int i=0; i<n; i++) {
 32         par[i]=i;
 33         hrank[i]=0;
 34     }
 35 }
 36 
 37 int find(int x)
 38 {
 39     if (par[x]==x) {
 40         return x;
 41     }
 42     else {
 43         return par[x]=find(par[x]);
 44     }
 45 }
 46 
 47 void unite(int x,int y)
 48 {
 49     x=find(x);
 50     y=find(y);
 51     if (x==y) {
 52         return;
 53     }
 54     if (hrank[x]<hrank[y]) {
 55         par[x]=y;
 56     }
 57     else {
 58         par[y]=x;
 59         if (hrank[x]==hrank[y]) {
 60             hrank[x]++;
 61         }
 62     }
 63 }
 64 
 65 bool same(int x,int y)
 66 {
 67     return find(x)==find(y);
 68 }
 69 
 70 bool cmp(const edge& e1,const edge& e2)
 71 {
 72     return e1.cost<e2.cost;
 73 }
 74 
 75 int kruskal()
 76 {
 77     sort(es, es+E, cmp);
 78     init(V);
 79     int res=0;
 80     for (int i=0; i<E; i++) {
 81         edge e=es[i];
 82         if (!same(e.u,e.v)) {
 83             unite(e.u, e.v);
 84             res+=e.cost;
 85         }
 86     }
 87     return res;
 88 }
 89 
 90 int main()
 91 {
 94     int n;
 95     int N,M,R;
 96     scanf("%d",&n);
 97     for (int i=0; i<n; i++) {
 98         scanf("%d%d%d",&N,&M,&R);
 99         V=N+M;
100         E=R;
101         for (int j=0; j<R; j++) {
102             scanf("%d%d%d",&x[j],&y[j],&d[j]);
103             es[j]=(edge){x[j],N+y[j],-d[j]};//N+y[j]……
104         }
105         printf("%d\n",10000*(N+M)+kruskal());
107     }
108     
109     return 0;
110 }
http://tech.artyoo.me/?p=60
struct edge {
    int u, v, cost;
};
int testcase, testcase_id;
int N, M, R;
int x[MAX_N], y[MAX_N], d[MAX_R];
struct edge es[MAX_R];
//并查集数据
int parent[MAX_N * 2];
bool cmp(const edge& e1, const edge& e2) {
    return e1.cost < e2.cost;
}
int find(int x) {
    return parent[x] == x ? x : (parent[x] = find(parent[x]));
}
int kruskal() {
    sort(es, es + R, cmp);
    for(int i = 0; i < N + M; i++)
        parent[i] = i;
    int ans = 0;
    for(int i = 0; i < R; i++) {
        edge e = es[i];
        int x = find(e.u);
        int y = find(e.v);
        if(x != y) {
            ans += e.cost;
            parent[x] = y;
        }
    }
    return ans;
}
int main() {
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    scanf("%d\n", &testcase);
    for(testcase_id = 0; testcase_id < testcase; testcase_id++) {
        scanf("%d %d %d\n", &N, &M, &R);
        for(int i = 0; i < R; i++) {
            scanf("%d %d %d\n", &x[i], &y[i], &d[i]);
            es[i] = (edge){x[i], N + y[i], -d[i]};
        }
        printf("%d\n", 10000 * (N + M) + kruskal());
    }
    return 0;   
}
http://blog.csdn.net/chenguolinblog/article/details/8043046
1 首先我们应该区分开男孩和女孩,只要将男孩的编号加上女孩的个数n,这样就可以做到男孩和女孩的编号是不同的。
2 题目中说了如果两个人有关系,并且其中一个人已经被选了那么选择另外一个人的时候只要10000-d即可。所以这就涉及到了两个人的关系问题,那么自然的想到了并查集来保存关系图。所以这n+m个人最后就可以被分到s个集合里面,每一个集合里面的人都是有关系的。那么这样我们只要求出s个集合的最小生成树相加,然后在加上s*10000(没有关系的时候选择一个人要10000),即为最后的答案。
void kruskal(){
     int ans = 0;
     sort(e , e+r , cmp);
     /*求出s个集合的最小生成树的和*/
     for(int i = 0 ; i < r ; i++){ 
        int root_x = find_Set(e[i].x);
        int root_y = find_Set(e[i].y);
        if(root_x != root_y){
          ans += e[i].value;
          union_Set(root_x , root_y);
        } 
     }
     /*求有几个集合*/
     int cnt = 0;
     int vis[MAXN];
     memset(vis , 0 , sizeof(vis));
     for(int i = 0 ; i < n+m ; i++){
        int tmp = find_Set(i);
        if(!vis[tmp]){
          cnt++;
          vis[tmp] = 1;
        }
     }
     printf("%d\n" , ans+10000*cnt);
}

int main(){
    int a , b , v;
    scanf("%d" , &t);
    while(t--){
        scanf("%d%d%d" , &n , &m , &r);
        init_Set();
        for(int i = 0 ; i < r ; i++){
           scanf("%d%d%d" , &a , &b , &v); 
           e[i].x = a;
           e[i].y = b+n;
           e[i].value = 10000-v;/*边的权值*/
        }
        kruskal();
    }
    return 0;
}
http://www.itwendao.com/article/detail/293915.html

Also check http://www.acmerblog.com/POJ-3723-Conscription-blog-1136.html
Read full article from 3723 -- Conscription

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts