poj1456Supermarket——并查集压缩查找

题目:http://poj.org/problem?id=1456

排序+贪心,每次选利润最大的,放在可能的最靠后的日期卖出,利用并查集快速找到下一个符合的日期。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,t,ans,fa[10005];
struct N{
	int p,d;
}a[10005],hp[10005];
int find(int x)
{
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
void pus(N x)
{
	t++;
	hp[t]=x;
	int now=t;
	while(now>1)
	{
		int tp=now/2;
		if(hp[now].p>hp[tp].p)
			swap(hp[now],hp[tp]),now=tp;
		else break;
	}
}
N del()
{
	N res=hp[1];
	swap(hp[1],hp[t]);
	t--;
	int now=1;
	while(now*2<=t)
	{
		int tp=now*2;
		if(tp<t&&hp[tp].p<hp[tp+1].p)tp++;
		if(hp[now].p<hp[tp].p)
			swap(hp[now],hp[tp]),now=tp;
		else break;
	}
	return res;
}
int main()
{
	while(scanf("%d",&n)==1)
	{
		ans=0;t=0;
		int dmx=0;
		memset(hp,0,sizeof hp);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&a[i].p,&a[i].d);
			pus(a[i]);
			if(a[i].d>dmx)dmx=a[i].d;
		}
		for(int i=1;i<=dmx;i++)fa[i]=i;
		for(int i=1;i<=n;i++)
		{
			N k=del();
			int f=find(k.d);
			if(f)
			{
				ans+=k.p;
//				fa[f]=find(k.d-1);
				fa[f]=find(f-1);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/Zinn/p/8439993.html

时间: 2024-10-09 04:56:28

poj1456Supermarket——并查集压缩查找的相关文章

普林斯顿公开课 算法1-8:并查集 快速查找

本节讲的是并查集的第一种实现方法,这种方法查找操作开销很小而合并操作开销比较大. 数据结构 假设有N个节点,那么该算法的数据结构就是一个包含N个整数的数组id[]. 判断操作 判断节点p和节点q是否相连就是判断id[p]和id[q]的值是否一致. 合并操作 合并节点p和节点q就是将id数组中所有的id[p]都修改为id[q]. 这样的话,每次合并都要遍历整个数组,修改多个值,因此开销比较大. 复杂度 合并一次的复杂度是N,如果需要合并N次,那么整个程序的复杂度就是N^2.这样的复杂度不适合应用于

并查集压缩路径

普通的并查集是这样婶的 void find1(int x) { int t=x; while(pre[t]!=t) { t=pre[t]; } } 如果复杂度比较高的话可以使用路径压缩(非递归版好理解,且不易爆栈),是这样婶的 void find1(int x) { int t=x; while(pre[t]!=t) { t=pre[t];//此时t就是最终的祖先 } int k=x;//k是最开始的那个点 while(t!=k) { int m=pre[k];//先保存一下结点的直接祖先: p

【BZOJ2594】水管局长加强版,LCT+并查集+二分查找位置

Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: LCT维护路径最小值 倒叙处理询问,就相当于往图里面加边. 实时维护最小值,即最小生成树,可以参照魔法森林. 最初的最小生成树操作用kruskal 最蛋疼的是处理询问时你不知道要删除哪条边,这给kruskal带来很大麻烦,所以我们对原来的每一条边使其编号小的端点在前,大的在后,然后以左端点为第一关键字,右端点为第二关键字排序,记录下每个左端点的所在区间,然后就可以通过二分查找的方式来确定是哪条边了

最小生成树个数 并查集压缩路径

1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5843  Solved: 2379[Submit][Status][Discuss] Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的 最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的最小生 成树可能很多,所以你只需要输出方案数对3101

并查集 压缩路径

int find(int x) { int k, j, r; r = x; while(r != parent[r]) //查找跟节点 r = parent[r]; //找到跟节点,用r记录下 k = x; while(k != r) //非递归路径压缩操作 { j = parent[k]; //用j暂存parent[k]的父节点 parent[k] = r; //parent[x]指向跟节点 k = j; //k移到父节点 } return r; //返回根节点的值 } void combin

并查集压缩hdu2818

#include<cstdio> #include<algorithm> using namespace std; int root[30010]; int num1[30010]; int num2[30010]; int find2(int x) { if(x != root[x]) { int fx = root[x]; root[x] = find2(fx); num1[x] += num1[fx]; } return root[x]; } void Union(int a

并查集(union-find set)与Kruskal算法

并查集 并查集处理的是集合之间的关系,即‘union' , 'find' .在这种数据类型中,N个不同元素被分成若干个组,每组是一个集合,这种集合叫做分离集合.并查集支持查找一个元素所属的集合和两个元素分别所属的集合的合并. 并查集支持以下操作: MAKE(X):建立一个仅有成员X的新集合. UNION(X,Y):将包含X和Y的动态集合合并为一个新集合S,此后该二元素处于同一集合. FIND(X):返回一个包含X的集合. 注意:并查集只能进行合并操作,不能进行分割操作. 并查集的实现原理 并查集

并查集——HDOJ-1232-畅通工程

并查集 并查集(Union-Find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题,在合并之前,需要先判断两个元素是否属于同一集合,这就需要用查找操作来实现.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等. 并查集的实现原理也比较简单,就是使用树来表示集合,树的每个节点就表示集合中的一个元素,树根对应的元素就是该集合的代表,如下图所示. 图中有两棵树,分别对应两个集合

POJ 1182 食物链 (带权并查集 &amp;&amp; 向量偏移)

题意 : 中文题, 直接去POJ  1182看即可 分析 : 通过普通并查集的整理归类, 能够单纯地知道某些元素是否在同一个集合内.但是题目不仅只有种类之分, 还有种类之间的关系, 即同类以及吃与被吃, 而且重点是题目问的并不是种类是否在一个集合内, 而是考察给出的关系是否矛盾.在解释之前, 先明白一个问题, 对于给出的关系, 如果我不能通过前面的信息来推断出来, 是不是不能够判断现在给出关系的对错?那就将这个信息作为真命题并存储起来, 方便后面判断.有了刚刚前面的陈述, 可以知道两个东西=>