嘘~ 正在从服务器偷取页面 . . .

POJ3723 Conscription 题解


POJ3723 Conscription 题解

题目链接:POJ3723 Conscription

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

首先,题目给出的格式 \(x_i\ y_i\ d_i\) 很像图论题

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

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

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

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

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

代码如下

#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;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录