問題 B: 分院帽 (hat)----------------------------思維(並查集+0/1揹包)

題目描述
在霍格沃茲魔法學校,每年都要舉行分院儀式。
分院帽今年不但負責將學生分到格蘭芬多,赫奇帕奇,拉文克勞以及斯萊特林四個學院。還要把一部分學生分到新建起的一所學院 —— StandardDeviation學院。
也就是離入學標準還差一點的學院。(因爲想來學習魔法的人真的太多了,大約有n人)但即使是這樣,也不能招收太多人,準確來說,學校打算招收m人。 可是,這是一所公平的學校,如果一些同分的學生中,只有一些被招收走了,那麼學校將會顏面盡失。老師十分不好辦。
根據學校的記錄,總共有k對人成績相同,老師必須讓錄取公平、同時又和預期招收人數相差最少。
大家都去學習魔法了,老師就把任務交給你了。請你求出最優的錄取人數。
輸入
第一行三個整數n,m,k
接下來k行每行兩個整數,a,b表示a,b兩人的成績相同
(n,m,k∈N*,1≤a,b≤n)
輸出
一行,表示既不讓同學們抗議,又與原來的m儘可能接近的選出學生的數目。(如果有兩種方案與m的差的絕對值相等,選較小的一種:)
樣例輸入 Copy
4 3 2
2 1
3 4
樣例輸出 Copy
2
提示
在這裏插入圖片描述
解析:
這道題一開始認爲最後的答案 不能超過預期人數m ,導致無限WA
先用並查集維護相同分數的個數,然後跑0/1揹包。
物品數量:集合個數
物品價值:每個集合的元素個數
揹包容量:n

最後我們還要判斷與m差值最小的答案(這時答案很可能超過m)

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e4+1000;
int fa[N];
ll size[N];
ll a[N];
int n,m,k;
ll dp[N];
int tot;
int find(int x)
{
	if(x!=fa[x]) return fa[x]=find(fa[x]);
	return fa[x];
}
int main()
{
	scanf("%d %d %d",&n,&m,&k);
	for(int i=0;i<=n;i++) fa[i]=i,size[i]=1;
	for(int i=1,u,v;i<=k;i++)
	{
		scanf("%d %d",&u,&v);
		int x=find(u);
		int y=find(v);
		if(x!=y)
		{
			fa[x]=y;
			size[y]+=size[x];
		//	size[x]=0;
		}
	}
	for(int i=1;i<=n;i++)
		if(find(i)==i) a[++tot]=size[find(i)];	

	dp[0]=0;
	for(int i=1;i<=tot;i++) 
		for(int j=n;j>=a[i];j--)
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
	ll ans=0x3f3f3f3f;
	ll pos;
	for(int i=0;i<=n;i++)
	{
		if(dp[i]!=0x3f3f3f3f)
		{
			
			if(abs(m-dp[i])<ans) ans=abs(m-dp[i]),pos=i;
		}
	}
	cout<<pos<<endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章