概述
A sequence S={s1,s2,...,sn} is called heapable if there exists a binary tree T with n nodes such that every node is labelled with exactly one element from the sequence S, and for every non-root node si and its parent sj , sj ≤ si and j < i hold. Each element in sequence S can be used to label a node in tree T only once.
Chiaki has a sequence a1,a2,...,an , she would like to decompose it into a minimum number of heapable subsequences.
Note that a subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.
序列 S={s1,s2,...,sn} 被称为 heapable ,当且仅当存在一个二叉树 T , n 个点均作为 T 的一个节点,且满足任意非根节点 si 和其父节点 sj , sj≤si 且 j<i 。
现在有一个序列 a1,a2,...,an ,相应将其分成若干个 heapable 的子序列,问使得子序列个数最少的策略。
解题思路
已知每个树上的节点
sj
均可有最多两个子节点
si
,要求
sj≤si
。将所有仍可连接子节点的节点用一个 set
来维护,保证其根据点对应的
ai
从小到大排序。对于一个新的
ai
来说,采用贪心策略将其作为最大的不大于
ai
值的节点的子节点,用 set.upper_bound()
可以在
O(set.size())
复杂度内实现查找。
需要注意的是,每个节点最多只能有两个子节点,故当某节点已经连接了两个子节点后,应将其从 set
中删除。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100000 + 10;
vector<int> v[N];
int n, a[N], cnt, dig[N];
struct Node {
int first, second;
} p;
bool operator<(Node x, Node y)
{
if(a[x.second] == a[y.second]) return x.second < y.second;
return a[x.second] < a[y.second];
}
set<Node > st;
set<Node >::iterator it;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
st.clear();
cnt = 0;
scanf("%d",&n);
memset(dig, 0, 4*n+4);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p.second = i;
it = st.upper_bound(p);
if(it==st.begin())
{
v[cnt].push_back(i);
p.first = cnt, p.second = i;
st.insert(p);
cnt++;
}
else
{
it--;
p = *it;
dig[p.second]++;
if(dig[p.second] == 2)
st.erase(it);
p.second = i;
st.insert(p);
v[p.first].push_back(i);
}
}
printf("%dn", cnt);
for(int i=0;i<cnt;i++)
{
printf("%d", v[i].size());
for(int j=0;j<v[i].size();j++)
printf(" %d", v[i][j]);
printf("n");
v[i].clear();
}
}
}
最后
以上就是怡然月饼为你收集整理的ZOJ 3963 Heap Partition(贪心)的全部内容,希望文章能够帮你解决ZOJ 3963 Heap Partition(贪心)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复