Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8243 | Accepted: 2859 |
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, 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
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
Source
这道题我从上午10点多开始做,到现在下午快三点了才AC。
好把,这回要认真写解题报告了!!!
大意:韦小宝为了反清复明打算征兵,但是他没有权势,所以只能花钱,征一个兵给人家10000RMB(先不讨论为什么是RMB吧)。韦爵爷多聪明的人啊,心里盘算着能不能省点,正好被他发现了一个省钱的方法。爵爷发现,只要把男丁喜欢的人招进来,那么想招这个男丁就只需要花10000-d,其中d是物质化了的此男对女的爱慕程度,同样,这个规律也适应于女丁。好,here is the question:爵爷该咋的才能花最少的钱招这写人呢???
有N男M女,既然是花最少的钱,何不利用最小生成树,将权值设为10000-d,直接kruskal一下。
嗯,这个想法是正确的,但是有漏洞。因为kruscal算法默认的是所有节点连通,但是这里的男女关系很可能是森林,,,你想想,假如这里的男女关系是连通的,可以构成一颗最小生成树,那,哇,这个村庄里的男女关系好复杂啊,哈哈。
那正确的解题思路是:求出所有的最大连通子图的权值和sum,然后用10000*(N+M)-sum。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define maxn 10000 #define maxr 50005 #define maxnr maxn+maxr+10 int n, m, r, tot; //1 ≤ N, M ≤ 10000 struct edge{ int from, to, c; edge(){ c = maxn; //初始化c=maxn的目的就是因为利用并查集时,我直接把男、女放在一个数组par中, } //女的下标是从maxn+i开始的 }cost[maxr * 2]; bool cmp(edge a, edge b){ return a.c > b.c; } int par[maxr*2], k; //并查集 int find(int x){ int r = x; while (par[r] != r)r = par[r]; int i = x, j; while (par[i] != r){ j = par[i]; par[i] = r; i = j; } return r; } void unite(int x, int y){ x = find(x); y = find(y); par[x] = par[y]; } bool same(int x, int y){ x = find(x); y = find(y); return x == y; } inline void init(){ for (int i = 0; i < maxr*2; i++)par[i] = i; tot = 0; k = 0; int x, y, d; for (int i = 0; i < r; i++){ scanf("%d %d %d", &x, &y, &d); cost[++k].from = x; cost[k].to = maxn + y; cost[k].c = d;// cost[++k].from = maxn + y; cost[k].to = x; cost[k].c = d;//look,从这里我就加了个偏移量maxn,并查集就可以用了 } sort(cost + 1, cost + k + 1, cmp); } void solve(){for (int i = 1; i <= k; i++){ if (!same(cost[i].from, cost[i].to)){ tot += cost[i].c; unite(cost[i].from, cost[i].to); } } printf("%d ", maxn*(n+m) - tot); } int main() { int t; scanf("%d", &t); while (t--){ scanf("%d %d %d", &n, &m, &r); init(); solve(); } // system("pause"); return 0; }