队列,BFS

CF962D Merge Equals

给定正整数序列 a1∼an 每次你需要找到序列中所有出现次数 ≥2 的元素中最小的元素 x,随后找到 x 在序列中的 2 个最小下标 i,j,删除 ai,将 aj改为 2x。

(感觉跟2048一样,显然是做不来的

反复进行如此操作,求序列最终的形态。
代码先出

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
int n,a[maxn],s;
map<int,int>m;
signed main()
{
	cin >> n;
	int s=n;
	for(int i=1;i<=n;i++)
	{
		cin >> a[i];
		if( m[ a[i] ] )
		{
			while( m[ a[i] ])
			{
				int index = m[ a[i] ];
				a[index]=0,s--,m[ a[i] ] =0;
				a[i] = 2*a[i];
			}
			m[ a[i] ]=i;
		}	
		else	m[ a[i] ]=i;
	}
	cout<<s<<endl;
	for(int i=1;i<=n;i++)
		if( a[i] )	cout<<a[i]<<" ";
}

题解:队列以a[ ]从小到大的方式排(堆),每有重复的,就删除第一个,使第二个变成2x,不是重复的,就弹出作为结果输出(优先队列)从队列中取出最小的元素 x 及其下标i,
检查队列中是否还有相同的元素 x ,
如果有,取出第二个相同的元素 x 及其下标j,并从队列中移除这两个元素。
将2x重新加入队列,下标为j。
重复上述步骤,直到队列中没有重复的元素。

UVA 540 团体队列

有t 个团队的人正在排长队。每有一个新来的人时,他会从队首开始向后搜寻,如果发现有队友正在排队,他就会插队到他队友的身后;如果没有发现任何一个队友排队,他就只好站在长队的队尾。
题解:因为有多个团队,不同团队的人要插入队列同一团队的人之后。将每个团体当成一个个体进行排队,然后再队每个团队内部进行一次排队。
先附上桶排列,大致理解了一下原理
桶排序原理
桶排序的基本思想是将待排序元素分布到有限数量的“桶”中,每个桶内包含一定范围的数据。接着对每个桶内部独立进行排序(通常使用其他简单排序算法),最后按顺序依次取出每个桶中的元素,即可得到全局有序序列。

#include<bits/stdc++.h>
using namespace std;
int n;
queue<int> Q;
queue<int> q[1006];
char ch[30];
int a[10000000];
int x;
int f;
int k = 1;
int main(void){
	while(scanf("%d",&n)){
		if(n == 0)//结束标志
			break;
		cout << "Scenario #" << k<<endl;	
		k ++;
		memset(a,0,sizeof(a));
		for(int i = 1;i <= 1005;++ i){
			while(!q[i].empty())
				q[i].pop();//清空
		}
			
		while(!Q.empty())
			Q.pop();//清空
		int h;
		for(int i = 0;i < n;++ i){
			scanf("%d",&h);
			for(int j = 0;j < h;++ j){
				scanf("%d",&x);
				a[x] = i; // 在数组a中记录每个成员所属的团队编号
			}
		}//while开始到这里都是在初始化,因为有多组数据
		while(scanf("%s",&ch)){
			if(ch[0] == 'S')//stop
				break;
			if(ch[0] == 'E'){
				scanf("%d",&x);
				if(q[a[x]].empty()){
					Q.push(x);
					q[a[x]].push(x);
				}//某个团队第一个人开始入队
				else{
					q[a[x]].push(x);//有队友直接插队
				}
			}
			if(ch[0] == 'D'){
				printf("%d\n",q[a[Q.front()]].front());//出队
				q[a[Q.front()]].pop();
				if(q[a[Q.front()]].empty())
					Q.pop();
			}
		}
		cout << endl;
	}
	
	return 0;
}
未掌握

CF96B Lucky number

大致题意:超级幸运数是指在其十进制表示中只包含数字4和7,并且4和7的个数相等的数。现在输入一个整数n,要寻找大于等于 n 的最小super lucky number。

最开始的思路:奇数加一位,偶数比较位数,再比较该数和其位数对应的幸运数大小,如果该位数最大的幸运数都比其小,就加一位输出幸运数,显然需要事先找出所在位数的全部幸运数,麻烦的离谱,差打表一辈子。
正确思路:队列先进先出,一步一步增加位数,注意以4开始来找最小的,模拟在数字后面添加一个 4,同时,stp 值增加 1,表示 4 的数量增加了,然后模拟在数字后面添加一个 7。同时,stp 值减少 1,表示 7 的数量增加了。

还是欠缺理解,给出代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
	ll x,stp;
};
int main(){
	ll n;
	cin>>n;
	queue<node>q;
	q.push((node){0,0});
	while(!q.empty()){
		node k=q.front();
		if(k.x>=n&&k.stp==0){//当前数值是否大于n以及是否 4 7 数量相同。
			cout<<k.x;
			return 0;
		}
		if(k.x<1e9){
			q.push((node){k.x*10+4,k.stp+1});
			q.push((node){k.x*10+7,k.stp-1});
		}
		q.pop();
	}
	return 0;
}

再附上打表的解法

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    for(int i=1;i<=5;i++){
        int a[10]={},t=0;
        for(int j=0;j<i;j++){//t从0开始
            a[t++]=4;
        }
        for(int j=0;j<i;j++){//t从6开始
            a[t++]=7;
        }
        do{
            for(int j=0;j<i*2;j++){
                cout<<a[j];
            }
            cout<<',';
        }while(next_permutation(a,a+i*2));
    }
    return 0;
}

顺带学习一下next_permutation
next_permutation 是 C++ 标准库中的一个函数,它用于生成给定序列的下一个按字典顺序排列的排列。如果存在这样的排列,该函数会修改序列,使其成为下一个排列,并返回 true;如果不存在下一个排列(即当前排列已经是最后一个排列),则该函数会将序列重新排列为第一个排列,并返回 false

函数的原型如下:

bool next_permutation(BidirectionalIterator first,
                     BidirectionalIterator last);
bool next_peritation(BidirectionalIterator first,
                     BidirectionalIterator last,
                     Compare comp);
  • BidirectionalIterator 是一个双向迭代器,可以指向序列中的元素。
  • firstlast 是定义序列范围的迭代器,[first, last) 表示序列的范围。
  • comp 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑,默认使用 operator<

使用 next_permutation 时,通常在一个循环中调用它,直到它返回 false 为止,这样可以遍历一个集合的所有排列。

示例代码:

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3};

    do {
        for (int i : v) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    } while (std::next_permutation(v.begin(), v.end()));

    return 0;
}

这段代码会输出集合 {1, 2, 3} 的所有排列。感觉理解这个就完事,然后有就true,没就false。

于是得到表:

long long ln[350]={47,74,4477,4747,4774,7447,7474,7744,444777,447477,447747,447774,474477,474747,474774,477447,477474,477744,744477,744747,744774,747447,747474,747744,774447,774474,774744,777444,44447777,44474777,44477477,44477747,44477774,44744777,44747477,44747747,44747774,44774477,44774747,44774774,44777447,44777474,44777744,47444777,47447477,47447747,47447774,47474477,47474747,47474774,47477447,47477474,47477744,47744477,47744747,47744774,47747447,47747474,47747744,47774447,47774474,47774744,47777444,74444777,74447477,74447747,74447774,74474477,74474747,74474774,74477447,74477474,74477744,74744477,74744747,74744774,74747447,74747474,74747744,74774447,74774474,74774744,74777444,77444477,77444747,77444774,77447447,77447474,77447744,77474447,77474474,77474744,77477444,77744447,77744474,77744744,77747444,77774444,4444477777,4444747777,4444774777,4444777477,4444777747,4444777774,4447447777,4447474777,4447477477,4447477747,4447477774,4447744777,4447747477,4447747747,4447747774,4447774477,4447774747,4447774774,4447777447,4447777474,4447777744,4474447777,4474474777,4474477477,4474477747,4474477774,4474744777,4474747477,4474747747,4474747774,4474774477,4474774747,4474774774,4474777447,4474777474,4474777744,4477444777,4477447477,4477447747,4477447774,4477474477,4477474747,4477474774,4477477447,4477477474,4477477744,4477744477,4477744747,4477744774,4477747447,4477747474,4477747744,4477774447,4477774474,4477774744,4477777444,4744447777,4744474777,4744477477,4744477747,4744477774,4744744777,4744747477,4744747747,4744747774,4744774477,4744774747,4744774774,4744777447,4744777474,4744777744,4747444777,4747447477,4747447747,4747447774,4747474477,4747474747,4747474774,4747477447,4747477474,4747477744,4747744477,4747744747,4747744774,4747747447,4747747474,4747747744,4747774447,4747774474,4747774744,4747777444,4774444777,4774447477,4774447747,4774447774,4774474477,4774474747,4774474774,4774477447,4774477474,4774477744,4774744477,4774744747,4774744774,4774747447,4774747474,4774747744,4774774447,4774774474,4774774744,4774777444,4777444477,4777444747,4777444774,4777447447,4777447474,4777447744,4777474447,4777474474,4777474744,4777477444,4777744447,4777744474,4777744744,4777747444,4777774444,7444447777,7444474777,7444477477,7444477747,7444477774,7444744777,7444747477,7444747747,7444747774,7444774477,7444774747,7444774774,7444777447,7444777474,7444777744,7447444777,7447447477,7447447747,7447447774,7447474477,7447474747,7447474774,7447477447,7447477474,7447477744,7447744477,7447744747,7447744774,7447747447,7447747474,7447747744,7447774447,7447774474,7447774744,7447777444,7474444777,7474447477,7474447747,7474447774,7474474477,7474474747,7474474774,7474477447,7474477474,7474477744,7474744477,7474744747,7474744774,7474747447,7474747474,7474747744,7474774447,7474774474,7474774744,7474777444,7477444477,7477444747,7477444774,7477447447,7477447474,7477447744,7477474447,7477474474,7477474744,7477477444,7477744447,7477744474,7477744744,7477747444,7477774444,7744444777,7744447477,7744447747,7744447774,7744474477,7744474747,7744474774,7744477447,7744477474,7744477744,7744744477,7744744747,7744744774,7744747447,7744747474,7744747744,7744774447,7744774474,7744774744,7744777444,7747444477,7747444747,7747444774,7747447447,7747447474,7747447744,7747474447,7747474474,7747474744,7747477444,7747744447,7747744474,7747744744,7747747444,7747774444,7774444477,7774444747,7774444774,7774447447,7774447474,7774447744,7774474447,7774474474,7774474744,7774477444,7774744447,7774744474,7774744744,7774747444,7774774444,7777444447,7777444474,7777444744,7777447444,7777474444,7777744444};

然后比较输出就完事

int main(){
    int n;
    cin>>n;
    for(int i=0;i<350;i++){
        if(ln[i]>=n){
            cout<<ln[i]<<endl;
            return 0;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值