数据结构 POJ 2431 Expedition 二叉树 并查集 POJ 1182 食物链

一.堆的实现

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);
}








你可能感兴趣的:(数据结构,ACM)