codevs 3372 選學霸(hash+並查集+多重揹包)
先通過並查集處理出來有多少種不同的集合,每個集合有多少人。一定要不要忘記了與別的沒有聯絡的獨立點。
並查集的時候可以通過hash處理出來每個數目相同的集合的個數。
這樣以人數為權值,個數為限制進行多重揹包,結果就是答案。
題目連結:http://codevs.cn/problem/3372/
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-8
#define M 1000100
#define LL long long
//#define LL long long
#define INF 0x3f3f3f
#define PI 3.1415926535898
#define mod 1000000007
const int maxn = 30010;
using namespace std;
int vis1[maxn];
int vis2[maxn];
int vis[maxn];
int num[maxn];
int dp[2*maxn];
int fa[maxn];
struct node
{
int snum;
int sum;
} p[maxn];
int n;
void init()
{
for(int i = 0; i <= n; i++) fa[i] = i;
memset(vis1, 0, sizeof(vis1));
memset(vis2, 0, sizeof(vis2));
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
}
int Find(int x)
{
if(x != fa[x]) fa[x] = Find(fa[x]);
return fa[x];
}
void add(int x, int y)
{
int x1, y1;
x1 = Find(x);
y1 = Find(y);
if(x1 != y1) fa[x1] = y1;
}
int main()
{
int m, k;
while(~scanf("%d %d %d",&n, &m, &k))
{
init();
int x, y;
for(int i = 0; i < k; i++)
{
scanf("%d %d",&x, &y);
vis[x] = 1;
vis[y] = 1;
add(x, y);
}
int ans = 0;
int xsum = 0;
for(int i = 1; i <= n; i++)
{
if(!vis[i])
{
xsum ++;
continue;
}
int s = Find(i);
vis1[s] ++;
}
for(int i = 1; i <= n; i++)
{
if(!vis1[i]) continue;
num[ans++] = vis1[i];
}
sort(num, num+ans);
for(int i = 0; i < ans; i++) vis2[num[i]]++;
int cnt = 0;
for(int i = 1; i <= n; i++)
{
if(!vis2[i]) continue;
p[cnt].snum = i;
p[cnt++].sum = vis2[i];
}
int v = 2*(m+1);
dp[0] = 1;
for(int i = 0; i < cnt; i++)
{
for(int j = v; j >= 0; j--)
{
if(!dp[j]) continue;
for(int kk = 1; kk <= p[i].sum; kk++)
{
if(kk*p[i].snum+j > v) break;
if(dp[kk*p[i].snum+j]) break;
dp[kk*p[i].snum+j] = 1;
}
}
}
int lx, rx;
for(int i = m; i >= 0; i--)
{
if(dp[i])
{
lx = i;
break;
}
}
for(int i = m; i <= 2*(m+1); i++)
{
if(dp[i])
{
rx = i;
break;
}
}
lx = max(lx, 0);
rx = min(rx, 2*(m+1));
int sx = abs(m-lx);
int sy = abs(rx-m);
if(sx <= xsum)
{
sx = 0;
lx = m;
}
else
{
sx -= xsum;
lx += xsum;
}
if(sy < sx)
{
cout<<rx<<endl;
continue;
}
cout<<lx<<endl;
}
return 0;
}
/*
10 4 9
8 2
1 5
5 10
9 7
10 3
3 4
4 6
8 9
6 8
0
5 3 3
1 2
2 3
3 4
4
*/
相關文章
- 01揹包、完全揹包、多重揹包詳解
- CODEVS 3269 混合揹包dev
- javascript演算法基礎之01揹包,完全揹包,多重揹包實現JavaScript演算法
- 【BZOJ 5003】與鏈 (多重揹包 dp)
- C129 並查集+01揹包 P1455 搭配購買並查集
- 多重揹包二進位制分解思想講解
- hihocoder 1285 智力競賽 (類多重揹包)
- 多重揹包動態規劃及空間優化動態規劃優化
- 多重揹包問題的單調佇列優化佇列優化
- POJ1276Cash Machine[多重揹包可行性]Mac
- Codeforces 148E Porcelain (預處理+多重揹包)AI
- 揹包問題(01揹包與完全揹包)
- 揹包DP——完全揹包
- 揹包DP——混合揹包
- 並查集到帶權並查集並查集
- 揹包 學習筆記筆記
- 分組揹包、完全揹包
- NOIP2012pj擺花[DP 多重揹包方案數]
- 【並查集】【帶偏移的並查集】食物鏈並查集
- 揹包
- 01揹包、有依賴的揹包
- poj1276 多重揹包問題(二進位制解決方案)
- 多重揹包O(N*V)演算法詳解(使用單調佇列)演算法佇列
- 並查集(一)並查集的幾種實現並查集
- 【學習筆記】並查集應用筆記並查集
- 3.1並查集並查集
- 並查集(小白)並查集
- 01 揹包
- 揹包DP
- [演算法學習筆記] 並查集演算法筆記並查集
- Codevs1378選課[樹形DP|兩種做法(多叉轉二叉|樹形DP+分組揹包)---(▼皿▼#)----^___^]dev
- 並查集(Union Find)並查集
- 並查集應用並查集
- The Door Problem 並查集並查集
- 並查集練習並查集
- 並查集的使用並查集
- 並查集—應用並查集
- 寫模板, 並查集。並查集