一.堆的实现
int heap[MXN],sz=0;
void push(int x){
int i=sz++;//自已节点的编号
while(i>0){
int p=(i-1)/2;//父亲节点的编号
if(heap[p]<=x)break;//如果已经没有大小颠倒则退出
heap[i]=heap[p];//父亲节点放下来,自已提上去
i=p;
}
heap[i]=x;
}
int pop(){
int ret=heap[0];//最小值
int x=heap[--sz];//要提到根的数值
int i=0;//从根开始向下交换
while(i*2+1<sz){
int a=i*2+1,b=i*2+2;//比较儿子的值
if(b<sz&&heap[b]<heap[a]) a=b;
if(heap[a]>=x) break;//如果已经没有大小颠倒则退出
heap[i]=heap[a];//把儿子的数值提上来
i=a;
}
heap[i]=x;
return ret;
}
二.POJ 2431 Expedition
题目大意:奶牛们刚刚在丛林里抢了一辆卡车。由于奶牛们的驾驶技术不高,卡车的油箱被刮漏了。现在油箱里有P(1 ≤ P ≤ 1,000,000)单位的油,每行驶一个单位,油箱就损失一个单位的油。而最近的城镇离这里有L(1 ≤ L ≤ 1,000,000)单位。现在道路上有N(1 ≤ N ≤ 10,000)个加油站,每个加油站有两个信息:一是其距离城镇的距离,二是加油站能供应的油量。现在油箱的容量无限,加油站一定会将能供应的油全部供应。奶牛们认为丛林里很危险,决定在能到达城镇的前提下,停留尽量少的加油站。计算奶牛们至少要停靠几个加油站。如果它们无法到达城镇,输出-1。
解法:当燃料为0时,选择加油量最大的加油站
int L,P,N,M;
int A[MXN+1],B[MXN+1];
void Fun(){
A[N]=L;
B[N]=0;
N++;
priority_queue<int> que;
int ans=0,pos=0,tank=P;
for(int i=0;i<N;++i){
int d=A[i]-pos;
while(tank-d<0){
if(que.empty()){
puts("-1");
return ;
}
tank+=que.top();
que.pop();
ans++;
}
tank-=d;
pos=A[i];
que.push(B[i]);
}
printf("%d\n",ans);
}
三.二叉树实现
struct node{
int val;
node *lch,*rch;
};
node *insert(node *p,int x){
if(p==NULL){
node* q=new node;
q->val=x;
q->lch=q->rch=NULL;
return q;
}
else{
if(x<p->val) p->lch=insert(p->lch,x);
else p->rch=insert(p->rch,x);
return p;
}
}
bool find(node *p,int x){
if(p==NULL) return false;
else if(x==p->val) return true;
else if (x<p->val) return find(p->lch,x);
else return find(p->rch,x);
}
node *remove(node *p,int x){
if(p== NULL) return NULL;
else if(x<p->val) p->lch=remove(p->lch,x);
else if(x>p->val) p->rch=remove(p->rch,x);
else if(p->lch==NULL){
node *q=p->rch;
delete p;
return q;
}
else if(p->lch->rch==NULL){
node *q=p->lch;
q->rch=p->rch;
delete p;
return q;
}
else{
node *q;
for(q=p->lch;q->rch->rch!=NULL;q=q->rch);
node *r=q->rch;
q->rch=r->lch;
r->lch=p->lch;
r->rch=p->rch;
delete p;
return r;
}
return p;
}
node *root=NULL;
root=insert(root,1);
find(root,1);
使用set
int main(){
set<int> s;
s.insert(3);
set<int>::iterator ite;
ite=s.find(1);
if(ite==s.end()) puts("not found");
s.erase(3);
if(s.count(3)!=0) puts("found");
}
使用map
int main(){
map<int,const char *> m;
m.insert(make_pair(1,"ONE"));
m.insert(make_pair(10,"TEN"));
m[10]="TEd";
map<int,const char*>::iterator ite;
ite=m.find(1);
puts(ite->second);
m.erase(1);
}
四.并查集
int par[MXN];//父亲
int rank[MXN];//树的高度
void init(int n){
for(int i=0;i<n;++i){
par[i]=i;
rank[i]=0;
}
}
int find(int x){
if(par[x]==x){
return x;
}else{
return par[x]=find(par[x]);
}
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return ;
if(rank[x]<rank[y]){
par[x]=y;
}else{
par[y]=x;
if(rank[x]==rank[y]) rank[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
}
五.POJ 1182 食物链
题意:
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
解法:
每只动物i创建3个元素i-A,i-B,i-C,
i-x 表示i属于种类x,并查集的每一个组表示组内的元素要么同时发生,要么同时不发生
(1)x和y属于同一种,合并x-A和y-A,合并x-B和y-B,合并x-C和y-C.
(2)x吃y,合并x-A和y-B,合并x-B和y-C,合并x-C和y-A
int N,K;
int T[MXK],X[MXK],Y[MXK];
void Fun(){
init(N*3);//元素x,x+N,X+2*N分别代表x-A,x-B,x-C
int ans=0;
for(int i=0;i<K;++i) {
int t=T[i];
int x=X[i]-1,y=Y[i]-1;//输入变成0,...,N-1范围
if(x<0||N<=x||y<0||N<=y){
ans++;
continue;
}
if(t==1){
if(same(x,y+N)||same(x,y+2*N)){//根据对称性只需判断(x-A,y-B)和(x-A,y-C)
ans++;
}
else{
unite(x,y);
unite(x+N,y+N);
unite(x+N*2,y+N*2);
}
}
else{
if(same(x,y)||same(x,y+2*N)){//根据对称性只需是否相同,存在反过来吃的情况
ans++;
}
else{
unite(x,y+N):
unite(x+N,y+2*N);
unite(x+2*N,y);
}
}
}
printf("%d\n",ans);
}