codevs 3372 选学霸(hash+并查集+多重背包)
来源:互联网 发布:mac中page up 编辑:程序博客网 时间:2024/06/01 08:48
先通过并查集处理出来有多少种不同的集合,每个集合有多少人。一定要不要忘记了与别的没有联系的独立点。
并查集的时候可以通过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 1000000007const 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 98 21 55 109 710 33 44 68 96 805 3 31 22 33 44*/
0 0
- codevs 3372 选学霸(hash+并查集+多重背包)
- Codevs 3372 选学霸(并查集+剩余空间最小的背包问题)
- 并查集+背包
- Codevs_P3372 选学霸(并查集+DP+背包)
- 【CodeVS】1553 互斥的数 开放性 按位dp+排序+单调性 并查集+Hash
- CODEVS-1074-食物链-并查集
- codevs 1074食物链 并查集
- codevs 1069关押罪犯 并查集
- CodeVS 1073家族(并查集)
- CodeVS 2597团伙(并查集)
- codevs 1069 关押罪犯 并查集
- Codevs 1073 家族 并查集
- CodeVS-2597 团伙(并查集)
- CODEVS 1073 家族 (并查集)
- CODEVS 1073 家族 并查集模板
- codevs 团伙(并查集)
- Codevs 2597 团伙(并查集)
- 【codevs】1703 家族 并查集
- 第十一周程序填充星号图(一)
- |控件随着窗口变化而变化|
- 关于已有项目转为maven的一点看法
- Android小分队教你怎么利用Bluebox Security 曝的漏洞
- Objective-C之成魔之路【7-类、对象和方法】
- codevs 3372 选学霸(hash+并查集+多重背包)
- android:descendantFocusability用法简析
- |非常实用的窗口变化时,控件也发生位置,大小变化 |基于对话框实现通过
- Java重载方法
- GetUtf8StrLen
- kali 顺利安装 VMtools
- |打开一个EXE可执行程序|实例打开一个系统计算器
- |tab控件的使用|
- 开源评测系统hustoj-代码解读1