10.10 高校模拟赛 贪心模拟+BFS+DP

来源:互联网 发布:云计算判断题 编辑:程序博客网 时间:2024/06/06 13:21

  • 出题人
  • Problem 1 painter
    • 题目来源
    • 题目描述
    • 题解
    • 代码
  • Problem 2 escape
    • 来源
    • 题目描述
    • 题解
    • 代码
  • Problem 3 balance
    • 题目来源
    • 题目描述
    • 题解
    • 代码

出题人

(排名不分先后):

Dewct http://loifrancis.gq/
zzk http://blog.csdn.net/loi__zzk
Cunese 大爷的csdn忘了,,行吧
whales http://blog.csdn.net/cherish_k

Problem 1 painter

题目来源:

http://poj.org/problem?id=2709

题目描述

杂货店出售一种由N(3<=N<=12)种不同颜色的颜料,每种一瓶(50ML),组成的颜料套装。你现在需要使用这N种颜料;不但如此,你还需要一定数量的灰色颜料。杂货店从来不出售灰色颜料——也就是它不属于这N种之一。幸运的是,灰色颜料是比较好配置的,如果你取出三种不同颜色的颜料各x ml,混合起来就可以得到xml的灰色颜料(注意不是3x)。
现在,你知道每种颜料各需要多少ml。你决定买尽可能少的“颜料套装”,来满足你需要的这N+1种颜料。那么你最少需要买多少个套装呢?
输入描述 输入包含若干组测试数据。每组数据一行:第一个数N, 3<=N<=12, 含义如上;接下来N+1个数,分别表示你需要的N+1种颜料的毫升数。最后一种是灰色。所有输入的毫升数<=1000.

注意:输入中不存在每个颜料套装的毫升数。由题意可知,每种各50ml,即一共50N ml
输出描述 每组数据输出一行,最少需要的套装数。
样例输入 3 40 95 21 0
7 25 60 400 250 0 60 0 500
4 90 95 75 95 10
5 0 0 0 0 0 333
0
样例输出 2
8
2
4
数据范围及提示 对于30%的数据 N=3
对于100%的数据3 <= N <= 100
数据最多不超过10组

题解:

先不考虑灰色,满足其他颜料至少需要ans;
每次操作,选取剩余颜料最多的三种,合成1单位灰色颜料,重新sort;
若不足三种且未合成足够的灰色,则ans++,每种颜料加50

代码:

直接sort的std#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int maxx,ans,n,gry;int b[10000];void init(){    maxx=0;    ans=0;}bool cmp(int a,int b){    return a>b;}int main(){    while(scanf("%d",&n)!=EOF){        if(n==0) return 0;        init();        for(int i=1;i<=n;i++) scanf("%d",&b[i]),maxx=max(maxx,b[i]);        scanf("%d",&gry);        ans=maxx/50;        if(maxx%50) ans++,maxx=ans*50;        for(int i=1;i<=n;i++) b[i]=maxx-b[i];        sort(b+1,b+n+1,cmp);        while(gry>0){            if(b[3]==0){                ans++;                for(int i=1;i<=n;i++) b[i]+=50;            }            b[1]--,b[2]--,b[3]--,gry--;            sort(b+1,b+n+1,cmp);        }        printf("%d\n",ans);    }}

我的cpp在poj上WA。。。。。随机数据太良心

考场代码需要改正的是:
1.记录每种颜料标号是不必要的,因为颜料的种类是无意义的,我们只关心它们是否不同。
2.没有特判灰色等于0,在剩余颜料不满两种的情况下,ans会+1;
调了一下午啊!!!!!!

考场 堆#include<iostream>#include<cstdio>#include<algorithm>#include<queue>using namespace std;const int N=150;int maxx,n,ned[N],ml[N],gry,cnt,ans;struct node{    int id,num;}tmp[5];priority_queue<node> Q;bool operator <(node a,node b){    return a.num<b.num;}void done(){    ans=maxx/50;    if(maxx%50) ans++,maxx=ans*50;    for(int i=1;i<=n;i++){        if(maxx-ned[i])        Q.push((node){i,maxx-ned[i]});    }    if(Q.size()<=2){        ans++;        for(int i=1;i<=n;i++) ml[i]=50;        while(!Q.empty()){            node u=Q.top();            Q.pop();            ml[u.id]+=u.num;        }        for(int i=1;i<=n;i++){            Q.push((node){i,ml[i]});        }    }    while(!Q.empty()){        for(int i=1;i<=3;i++){            tmp[i]=Q.top();            Q.pop();        }        cnt+=1;        if(cnt>=gry) return ;        for(int i=1;i<=3;i++){            if(tmp[i].num-1)            Q.push((node){tmp[i].id,tmp[i].num-1});        }        if(Q.size()<=2){            ans++;            for(int i=1;i<=n;i++) ml[i]=50;            while(!Q.empty()){                node u=Q.top();                Q.pop();                ml[u.id]+=u.num;            }            for(int i=1;i<=n;i++){                Q.push((node){i,ml[i]});            }        }    }    return ;}void init(){    while(!Q.empty()) Q.pop();    ans=0;    maxx=0;    cnt=0;    for(int i=1;i<=3;i++) tmp[i].id=0,tmp[i].num=0;}int main(){    freopen("painter.in","r",stdin);    freopen("painter.out","w",stdout);    while(scanf("%d",&n)!=EOF){        if(n==0) return 0;        init();        for(int i=1;i<=n;i++) {            scanf("%d",&ned[i]);            maxx=max(maxx,ned[i]);        }        scanf("%d",&gry);        done();        printf("%d\n",ans);    }    return 0;}
改 √ 了的堆#include<iostream>#include<cstdio>#include<algorithm>#include<queue>using namespace std;const int N=150;int maxx,n,ned[N],ml[N],gry,cnt,ans,tot;int tmp[5];priority_queue<int> Q;void add(){    ans++;    tot=0;    for(int i=1;i<=n;i++) ml[i]=50;    while(!Q.empty()){        int u=Q.top();        Q.pop();        ml[++tot]+=u;    }    for(int i=1;i<=n;i++){        Q.push(ml[i]);    }}void done(){    ans=maxx/50;    if(maxx%50) ans++,maxx=ans*50;    if(gry==0) return ;//!!!!!!!!!!    for(int i=1;i<=n;i++){        if(maxx-ned[i]>0)        Q.push(maxx-ned[i]);    }    if(Q.size()<=2){        add();    }    while(!Q.empty()){        for(int i=1;i<=3;i++){            tmp[i]=Q.top();            Q.pop();        }        cnt+=1;        if(cnt>=gry) return ;        for(int i=1;i<=3;i++){            if(tmp[i]-1>0)            Q.push(tmp[i]-1);        }        if(cnt<gry&&Q.size()<=2){            add();        }    }}void init(){    while(!Q.empty()) Q.pop();    ans=0;    maxx=0;    cnt=0;}int main(){    while(scanf("%d",&n)!=EOF){        if(n==0) return 0;        init();        for(int i=1;i<=n;i++) {            scanf("%d",&ned[i]);            maxx=max(maxx,ned[i]);        }        scanf("%d",&gry);        done();        printf("%d\n",ans);    }    return 0;}

Problem 2 escape

来源:

http://hzwer.com/4598.html

题目描述

给出数字N(1<=N<=10000),X(1<=x<=1000),Y(1<=Y<=1000),代表有N个敌人分布一个X行Y列的矩阵上,矩形的行号从0到X-1,列号从0到Y-1再给出四个数字x1,y1,x2,y2,代表你要从点(x1,y1)移到(x2,y2)。在移动的过程中你当然希望离敌人的距离的最小值最大化,现在请求出这个值最大可以为多少,以及在这个前提下,你最少要走多少步才可以回到目标点。注意这里距离的定义为两点的曼哈顿距离,即某两个点的坐标分为(a,b),(c,d),那么它们的距离为|a-c|+|b-d|。
输入描述 第一行给出数字N,X,Y
第二行给出x1,y1,x2,y2
下面将有N行,给出N个敌人所在的坐标

输出描述 在一行内输出你离敌人的距离及在这个距离的限制下,你回到目标点最少要移动多少步。
样例输入 2 5 6
0 0 4 0
2 1
2 3

样例输出 2 14
数据范围及提示
30%: n=1
100%: 1<=n<=1000, 1<=x<=1000, 1<=y<=1000

题解:

预处理出每个点到它最近敌人的距离(把敌人坐标丢进队列里,做bfs),将整张图扫一遍。
二分答案,按照预处理出的距离,判断某点是否能走,bfs;

注意:
二分判断时,首先判断起点是否合法!!

考试的时候,没有预处理,每二分一次重新标记图,成功tle!

代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<queue>#include<cstring>using namespace std;struct node{    int x,y,step;};bool used[1005][1005];int dis[1005][1005]; queue<node> Q;int n,X,Y,x1,x2,y1,y2,ans,a,b;int dx[10]={0,1,0,-1,0},dy[10]={0,0,1,0,-1};bool can(int x,int y,int mid){    if(x>=0&&x<X&&y>=0&&y<Y&&!used[x][y]&&dis[x][y]>=mid) return true;    return false;}void init(int mid){    memset(used,0,sizeof(used));    while(!Q.empty()) Q.pop();    ans=0;}bool check(int x){    init(x);    Q.push((node){x1,y1,0});    used[x1][y1]=1;    if(dis[x1][y1]<x) return false;    while(!Q.empty()){        node u=Q.front();        if(u.x==x2&&u.y==y2){            ans=u.step;            return true;        }        Q.pop();        for(int i=1;i<=4;i++){            int xx=u.x+dx[i],yy=u.y+dy[i];            if(can(xx,yy,x)){                used[xx][yy]=1;                Q.push((node){xx,yy,u.step+1});            }        }    }    return false;}void done(){    while(!Q.empty()){        node u=Q.front();        Q.pop();        for(int i=1;i<=4;i++){            int xx=u.x+dx[i],yy=u.y+dy[i];            if(xx>=0&&xx<X&&yy>=0&&yy<Y&&!used[xx][yy]){                dis[xx][yy]=u.step+1;                used[xx][yy]=1;                Q.push((node){xx,yy,u.step+1});            }        }    }    return ;}int main(){    freopen("escape.in","r",stdin);    freopen("escape.out","w",stdout);    scanf("%d%d%d",&n,&X,&Y);    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);    for(int i=1;i<=n;i++){        scanf("%d%d",&a,&b);        Q.push((node){a,b,0});        dis[a][b]=0;        used[a][b]=1;    }    done();    int l=-1,r=100000000+800;    while(r-l>1){        int mid=r+l>>1;        if(check(mid)) l=mid;        else r=mid;    }    check(l);    printf("%d %d\n",l,ans);    return 0;}

Problem 3 balance

题目来源:

https://vjudge.net/problem/POJ-1837

题目描述

有一个天平,天平左右两边各有若干个钩子,总共有C个钩子,有G个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数。
输入描述 第一行两个数c, g分别代表钩子数和钩码数
第二行c个数,表示每个钩子距离天平中央的距离c[i],负数表示在左边,正数表示在右边
第三行g个数,表示每个钩码的重量w[i]
输出描述 输出总方案数
样例输入
2 4
-2 3
3 4 5 8

样例输出 2

数据范围及提示 30%: c<=9, g<=9
100%: c<=20, g<=20, -15<=c[i]<=15, w[i]<=25

题解:

一道精彩的初中物理题
设置状态dp[i][j]表示放了i个钩码,平衡度为j的方案数;
平衡度的定义为:右边-左边
由此可知:左边重 j<0,右边重 j>0,平衡 j=0
由数据范围可以推测出,平衡度的绝对值小于7500
为了避免负数作为下标,将平衡度均+7500

枚举钩码    枚举放在哪个位置        枚举此时的平衡度        转移

总结一下,本题主要难在设计状态。

代码:

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int g[25],w[25],dp[25][15020];int n,m;int main(){    freopen("balance.in","r",stdin);    freopen("balance.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)   scanf("%d",&g[i]);    for(int i=1;i<=m;i++)   scanf("%d",&w[i]);    dp[0][7500]=1;    for(int i=1;i<=m;i++){        for(int j=1;j<=n;j++){                for(int k=0;k<=15000;k++){                    if(k-w[i]*g[j]>=0)                        dp[i][k]+=dp[i-1][k-w[i]*g[j]];                }        }    }    printf("%d",dp[m][7500]);    return 0;}

result 100+40+0;
T1由于数据水,成绩不准确;

阅读全文
0 0