POJ3723 Conscription 题解

POJ3723 Conscription

题目链接:POJ3723 Conscription

题意:要招 n n n 个女的, m m m 个男的,原价 10000 10000 10000$,如果招了关系亲密的(男女)人可以降价,求最小花费

首先,题目给出的格式 x i   y i   d i x_i\ y_i\ d_i xi yi di 很像图论题

我们可以把每个人看作一个结点,为了防止男女编号相同的人搞混了,我们可以让女的编号为 1 ∼ n 1 \sim n 1n ,男的编号为 n + 1 ∼ m n+1 \sim m n+1m ,显然这题要我们选出所有的结点且花费最小

我们可以发现答案如果存在环则会产生矛盾,例如:a招了b,b招了c,c招了a,这说不通

那是最小生成树吗?不一定

我们可以发现给定的这张图不一定是连通图,而我们要求的是花费最小的树型结构(感性理解下),那么这就是最大权森林问题,同样可以用最小生成树来求解(注:边权设为 − d i -d_i di​​​)

由于不一定是树,所以不需要记录连了多少边

代码如下

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
// POJ不给用万能头文件 qwq
using namespace std;
#define int long long
#define R register
#define MAXN (int)(2e4+50)
#define MAXM (int)(5e4+50)
template<typename T>inline void read(R T &k)
{
	R char ch=getchar();R T x=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	k=x*f;
}
int Q,n,m,r;
int f[MAXN];
int find(R int x)
{return f[x]==x?x:f[x]=find(f[x]);}
inline void merge(R int u,R int v){f[find(u)]=find(v);} // 并查集
struct Edge
{
	int u,v,w,next;
	void clear(){u=v=w=next=0;} // 清空
	bool operator<(const Edge &o)const
	{return w<o.w;}
}e[MAXM];
int head[MAXN],pos=1;
void add(R int u,R int v,R int w)
{
	e[pos]={u,v,w,head[u]};
	head[u]=pos++;
}
int kruskal()
{
	R int res=0;
	sort(e+1,e+r+1);
	for(R int i=1; i<=r; i++)
	{
		R int u=e[i].u,v=e[i].v,w=e[i].w;
		if(find(u)!=find(v))
		{merge(u,v);res+=w;}
	}
	return res;
}
void proc()
{
	read(n);read(m);read(r);pos=1;
	for(R int i=1; i<=n+m; i++)
		f[i]=i;
	for(R int i=1; i<=r; i++)
		e[i].clear();
	for(R int i=1,u,v,w; i<=r; i++)
	{
		read(u);read(v);read(w);
		v+=n;++u;++v; // 题目是从0开始编号的,我不喜欢QwQ
		add(u,v,-w);
	}
	printf("%lld\n",10000ll*(n+m)+kruskal()); // 别忘了加上每个人10000$的原价
}
signed main()
{
	read(Q);
	while(Q--)proc(); // 多组数据
	return 0;
}

转载请说明出处

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值