priority_queue(优先队列)uva136 uva10603

优先队列嘛,大家都知道队列吧。对 就是那个queue同志。从头和尾都可以取,但是但是呢。如果你要取特定的的值呢。例如你要取一个队列中最大的或最小的那个呢。这时候队列就不是很适用了。即使能用复杂度也到n^2了(就是遍历)而且也麻烦。而优先队列(priority-queue)哎,顾名思义就是在queue前面加了个优先,哈哈。大概就是在结构体里面加个bool operator<(node a,node b){ return a.s<b.s}就是最顶上一个换成最小的依次向下。换成大于号就依次向下。不过今天做了个题目,大概就是给你三杯子,最后一个杯子里是充满水的,而前俩个是空的,如何每次倒水的操作只能是将该杯子倒满或者把自己全部倒掉。如何让你量取出d升水。每个杯子均无刻度,如果取不到就取最接近的,就是改变一个状态

#include"iostream"
#include"string"
#include"cstring"
#include"algorithm"
#include"cmath"
#include"map"
#include"queue"
#include"vector"
#include"cstdio"
#include"cstdlib"
#include"set"
#include"sstream"
#include"stack"


typedef long long ll ;

using namespace std;
int vis[205][205],ans[205],st[3];  //可以将当前概念化为一个二维数组
struct node {
int str[3],s; //str[3]代表当前状态 ,s表示当前状态倒的水 
bool operator < (const node &rhs) const{  //这个其实就是重载符,相当于俩个比较了
return s>rhs.s;   //优先队列,优先输出大的 
}
}; 
void update(const node &u){
for(int i=0;i<3;i++){
int p=u.str[i]; //得到当前水需要的水量
if(ans[p]<0||u.s<ans[p]) ans[p]=u.s;  // 更新答案 
}
}
void solve(int a,int b,int c,int d){
    st[0]=a,st[1]=b,st[2]=c; //记录初始状态 
    fill(vis,0);  //类似地图,避免重复 
    fill(ans,-1);
    priority_queue<node>Q;
    node sta;
    sta.s=0;
    sta.str[0]=0,sta.str[1]=0,sta.str[2]=c;
    Q.push(sta);
    vis[0][0]=1;
    while(!Q.empty()){
    node u=Q.top(); Q.pop();
    update(u);
    if(ans[d]>=0) break; //可以取到了,跳出,当前
    for(int i=0;i<3;i++){
    for(int j=0;j<3;j++){
    if(i!=j){  //表示从一个i杯子倒水到另一个j杯子,肯定不可能倒给自己啊
    if(u.str[i]==0||u.str[j]==st[j]) continue;  //被倒的是满的肯定不能倒啊
    int num=min(st[j],u.str[i]+u.str[j])-u.str[j];  //选取倒的水量
    node u2;
    memcpy(&u2,&u,sizeof(u));  //将结构体复制过来 ,node u2=u?嘿嘿
    u2.s=u.s+num;
    u2.str[i]-=num;
    u2.str[j]+=num;  //倒水改变容量
    if(!vis[u2.str[0]][u2.str[1]]){ //如果该状态未访问,则遍历 
    vis[u2.str[0]][u2.str[1]]=1;
    Q.push(u2);
    }
}
    }
    }
    }
    while(d>=0){ //千万不要while(d--),嘿嘿
    if(ans[d]>=0){ //找到最接近的答案,不一定能倒满d 
    printf("%d %d\n",ans[d],d);
    return;
    }
    d--;
    }
}
int main(){
int T;
int a,b,c,d;
cin>>T; 
while(T--){
cin>>a>>b>>c>>d;
solve(a,b,c,d);
}
return 0;

还有个题目就是丑数的

让你求第1500个只能整除的奇数只有2,3,5的数。当然就是1乘2,3,5,得到新的三个,然后在这个基础是扩展,必然是只能的到需要的数。很容易想到用set,但是可能会出现重复的情况,就要检测一次是否会重合,所以要用一个优先队列存储数字。肯定是优先取最小的。这里唯一一个priority_queue<ll,vector<ll>,greater<ll> >q;就是这个vector是不定长数组,然后greater是使队列中最小的在最上面,最大的在最下面。同理要是less的话就与此相反。下面附上代码

#include"queue"

#include"vector"

#include"set"

#include"iostream"

#include"cstdio"

typedef long long ll ;

using namespace std;//优先队列  priority_queue
set<ll >Q; 
priority_queue<ll,vector<ll>,greater<ll> >q;
const int str[3]={2,3,5};
int main(){
Q.insert(1); 
q.push(1);
for(int i=1;;i++){
ll m=q.top(); q.pop();
if(i==1500){
printf("The 1500'th ugly number is %lld.\n",m);
break;
}
for(int j=0;j<3;j++){
ll x=m*str[j];
if(!Q.count(x)){
q.push(x);
Q.insert(x);
}
}
}
return 0;

其实感觉还是蛮好理解的,就是取到第1500个的时候就可以输出的嘛

(第一次写,有点菜,见谅,哈哈\n);


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值