P3566 [POI2014] KLO-Bricks 题解

文章讲述了如何使用贪心策略和优先队列解决一道关于颜色砖块排列的问题,保证每相邻两块颜色不相同。通过先放最少和最多的砖块,利用优先队列实时更新,找出最优解或判断无解。

P3566 [POI2014] KLO-Bricks 题解

大致意思:

现在有 nnn 种颜色的砖块,第一个必须放第 ppp 种颜色,最后一定得放第 qqq 种颜色,剩余中间的需要自己构造,使得每相邻两个砖块的颜色不相等,有解随便输出任意一种,无解则输出 000

大致思路:

这是一道很好的贪心构造题,最优的方案,肯定就是先放最少最多,用最多的来分隔少的,因为这样最多的可以放置的更为均匀,以达到我们实现最优方案的目的,不然会导致多的前面放的过少,后面聚在一堆,实现出来的代码显示的是无解。当然如果当前最多的颜色与前面一项相等,那么我们要取一二大的,以此类推。

而我们知道了,想要实现此方法需要一边运行放颜色,一边排序,如果直接用用排序函数,占用时间太大,肯定会超时,那么我们就可以用到优先队列,它是可以边运行边排序的。

我们可以用变量 sss,记录总砖块数,接着通过循环实现放砖块:

  • 当前最多的砖块他的下标与前面相等,那么我可以用 ttt 记录最多砖块的数量,把它从队列中移除,找到第二多的砖块,将这个砖块的数量减 111

  • 当前最多的砖块他的下标与前面不相等,直接用此砖块,将这个砖块的数量减 111

当然,在过程中我们还要判断,本种砖块数是否大于 000,和此时队列里还有没有砖块,如果没有砖块,则无解。

代码实现:

#include<bits/stdc++.h>
using namespace std;
int n,p,y,s;
int ar[1000005];
bool f;
struct node{
	int x;
	int id;
}a[1000005];
bool operator <(node l,node r){
    if (l.x != r.x) return l.x<r.x;
	if (l.id == y) return 0;
    if (r.id == y) return 1;
    return 0; 
}
priority_queue<node> q;

int main(){
	cin>>n>>p>>y;
	for(int i=1;i<=n;i++){
		cin>>a[i].x;
		if(i==p) a[i].x--;
		if(i==y) a[i].x--;
		s+=a[i].x;
		a[i].id=i;
		q.push(node{a[i].x,i});
	}

	int u=p;
	ar[s+2]=y;
	for(int i=2;i<=s+1;i++){
		node t=q.top();q.pop();
		if(t.x>0) t=t;
        else{
            f=1;
            break;
        }
		if(t.id!=u&&t.x>0){
			ar[i]=t.id;
			q.push(node{t.x-1,t.id});
			u=ar[i];
		}else if(q.size()&&t.x>0){
			node v=q.top();
			q.pop();
			ar[i]=v.id;
			q.push(node{v.x-1,v.id});
			q.push(node{t.x,t.id});
			u=ar[i];
		}else if(!q.size()){
			f=1;
			break;//不加 RE,我找了两位大佬才调出来
		}
	}
	if(f){
		cout<<"0";
		return 0;
	}
	for(int i=1;i<=s+1;i++){
		if(ar[i]==ar[i+1]){
			f=1;
		}
	}
	if(f){
		cout<<"0";
		return 0;
	}
	cout<<p<<" ";
	for(int i=2;i<=s+1;i++){
		cout<<ar[i]<<" ";
	}
	cout<<ar[s+2];
	return 0;
}

这样这道题就结束啦!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值