并查集+二分 hnu13433 Dragons
来源:互联网 发布:win7进入windows后黑屏 编辑:程序博客网 时间:2024/05/22 03:17
传送门:点击打开链接
题意:有N个城市,M条双向边,K条龙。
第i条龙在Ci城市,初始有Si个头,如果龙还活着,每一分钟增加Ci个头
一个勇士1分钟可以砍一个龙的头,也可以选择移动到当前城市周围相邻的城市去
不限定时间的前提下,至少要召集多少勇士,才能把所有的龙全部杀掉
勇士的初始位置可以是任意的
思路:这道题出的非常好,但是却一下子很难想。
首先,可以想到,这个图可能并不完全连通,那么就会有很多个连通分量,这些连通分量之间没有联系,那么勇士就不能跨连通分量转移,所以对于多个连通分量,肯定是要肯开处理,然后积累总和的。
其次,怎样才能将龙给杀掉呢?有两种办法。在第1秒的时候,就直接有Si个勇士,直接把初始血量打成0,就杀了。或者是,在整个连通分量中勇士的个数超过了Ni的前提下,肯定能将这条龙杀了,因为时间是无限的,我只要召集整个连通分量中的勇士,然后每分钟造成的伤害比回复快,那么肯定是可以的。
想到这里,我们就能想到了,之所以告诉你边,完全只是要你分别求出连通分量而已。。所以我们使用并查集将n个点分开成多个连通分量。
对于一个连通分量中,,到底应该派多少勇士呢。因为有两种决策,然后当时卡死在这里,,最初想利用贪心策略,但是想了很久都没有构造出来,后来发现如果去二分其实特别简单。那么如何二分呢。二分的对象是,对于这个连通分量中,至少需要m个勇士,才能将这个连通分量中的龙全部杀掉。那么对于Ni+1<=m的那些龙,肯定是可以杀死的,因为上面的策略2嘛。对于Ni+1>m的龙,如果想只用m个勇士就能把这条龙杀了的话,那么就必须需要Si个勇士,直接在第一分钟就杀了它。所以,二分中的验证函数,就是积累Ni+1>m的龙的Si之和,与m去做比较,看大小关系即可~
#include<map>#include<set>#include<cmath>#include<stack>#include<queue>#include<cstdio>#include<cctype>#include<string>#include<vector>#include<cstring>#include<iostream>#include<algorithm>#include<functional>#define fuck printf("fuck")#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w+",stdout)using namespace std;typedef long long LL;const int MX = 2000 + 5;vector<int>G[MX];int P[MX], A[MX];struct Data { int C, S, N; Data() {} Data(int _C, int _S, int _N) { C = _C; S = _S; N = _N; }} D[MX];int find(int x) { return P[x] == x ? x : (P[x] = find(P[x]));}bool check(int id, int x) { int sum = 0; for(int i = 0; i < G[id].size(); i++) { int v = G[id][i]; if(x < D[v].N + 1) sum += D[v].S; } return sum <= x;}int main() { int n, m, k; //FIN; while(~scanf("%d%d%d", &n, &m, &k), n) { for(int i = 1; i <= n; i++) { P[i] = i; G[i].clear(); } for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); int p1 = find(u), p2 = find(v); P[p1] = p2; } int rear = 0; for(int i = 1; i <= n; i++) { if(i == find(i)) A[++rear] = i; } for(int i = 1; i <= k; i++) { int ci, si, ni; scanf("%d%d%d", &D[i].C, &D[i].S, &D[i].N); int p = find(D[i].C); G[p].push_back(i); } int ans = 0; for(int i = 1; i <= rear; i++) { int l = 0, r = 1e9, m, ret; while(l <= r) { m = (l + r) >> 1; if(check(A[i], m)) { ret = m; r = m - 1; } else l = m + 1; } ans += ret; } printf("%d\n", ans); } return 0;}
- 并查集+二分 hnu13433 Dragons
- poj3657 二分+并查集
- [二分][并查集]周末出游计划
- POJ 2253 Frogger(并查集+二分)
- UVALive_6168_Fat Ninjas(二分+并查集)
- HDU1598 并查集 或 二分+DFS
- HDU 3938 离线并查集+二分
- 4025: 二分图 分治+并查集
- hdu3081 二分+并查集+最大流
- (并查集 or BFS+二分)HDU5652
- 关押罪犯 并查集+二分
- HDU3081-并查集+最大二分匹配
- HDU 5652 二分+并查集+BFS
- 化名-并查集+二分查找
- ssl 2785 询问 并查集+二分
- 11.01 早上 枚举+二分+并查集
- hdu 3081 【二分匹配+并查集+删边||最大路+并查集+二分枚举】
- Dragons
- 第四周实践项目--单链表的建立
- 建设单链表算法库
- 第六周项目3多项式求和
- 高斯消元低精度模板
- 第四章项目3-单链表应用
- 并查集+二分 hnu13433 Dragons
- 第三周--【项目 - 求集合并集】
- 第4周项目1 建立单链表
- 左旋右旋 如何写好不犹豫写好代码
- iOS9的新特性
- 【状态压缩&位运算】poj 2436 Disease Management
- 第四周:建立单链表
- poj 3421
- LeetCode 069 Sqrt(x)