算法设计与分析期末上机考试总结

来源:互联网 发布:青瓦台风水 知乎 编辑:程序博客网 时间:2024/05/21 04:19
A约翰的零花钱 上机考试(2016)
时间限制2000ms内存限制65536KB
题目描述
约翰要对自己的花费进行规划。他首先计算得到了后面N(1<=N<=100000)天的花费money(1<=money<=10000)。然后将这N天恰好分成M(1<=M<=N)个周期。每个周期包含一个或多个连续的天数。每天只能包含在一个周期内。最后计算出每个周期的花费和。他会以最大的一个周期的花费和向妈妈要零花钱。但是妈妈说,这样太浪费钱了。所以,她让约翰对合理安排周期,使最终的给的零花钱最少。注意:这N天花费的顺序是不能改变的。
输入格式
第一行为两个数字N M,接下来有N行,每行一个整数。对于40%的数据,N<=100;对于70%的数据,N<=10000;对于100%的数据,N<=100000。
输出格式
妈妈给的最小零花钱。
输入样例
7 5
100
400
300
100
500
101
400
输出样例
500
最小零花钱的最小值是每天花费中的最大值,此时M=N;最小零花钱的最大值是所有花费的和,此时M=1。据此进行二分搜索判断最小零花钱的值。
AC代码:
#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int MAXN=100010;int n,m;int money[MAXN];long long int low,high,mid;bool judge(int k){int group=1;    long long int sum=0;    for(int i=n-1;i>=0;i--) {        if(sum+money[i]>k) {            group++;            sum=money[i];            if(group>m) return false;        }        else sum+=money[i];    }    return true; }int main(){low=-1,high=0;   scanf("%d %d",&n,&m);    for(int i=0;i<n;i++) {scanf("%d",&money[i]);  if(low<money[i]) low=money[i];  high=high+money[i]; }  while(low<high) { mid=(low+high)/2;   if(judge(mid)) high=mid;     else low=mid+1;     }     cout<<high<<endl;}
B盖房子 上机考试(2016)
时间限制1000ms内存限制65536KB
题目描述
永恒の灵魂最近得到了面积为n*m的一大块土地(高兴ING^_^),他想在这块土地上建造一所房子,这个房子必须是正方形的。但是,这块土地并非十全十美,上面有很多不平坦的地方(也可以叫瑕疵)。这些瑕疵十分恶心,以至于根本不能在上面盖一砖一瓦。他希望找到一块最大的正方形无瑕疵土地来盖房子。不过,这并不是什么难题,永恒の灵魂在10分钟内就轻松解决了这个问题。现在,您也来试试吧。
输入格式
输入文件第一行为两个整数n,m(1<=n,m<=200),接下来n行,每行m个数字,用空格隔开。0表示该块土地有瑕疵,1表示该块土地完好。
输出格式
一个整数,最大正方形的边长。
输入样例
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
输出样例
2
很简单的搜索。
AC代码:
#include<iostream>#include<algorithm>using namespace std;int graph[1010][1010];  int main(){    int n,m;    int ans=0;    cin>>n>>m;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            cin>>graph[i][j];            if(graph[i][j]==1) ans=1;        }    }    if(ans==0)    {        cout<<ans<<endl;        return 0;    }    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            if(graph[i][j])            {                int ii,jj;                bool flag=1;                for(int k=1;i+k<=n&&j+k<=m;k++)                {                    for(ii=i;ii<=i+k&&flag;ii++)                    {                        for(jj=j;jj<=j+k&&flag;jj++)                        {                            if(!graph[ii][jj]) flag=0;                        }                    }                    if(flag==0)                    {                        ans=max(ans,k);                        break;                    }                }            }        }    }    cout<<ans<<endl;}
C切蛋糕 上机考试(2016)
时间限制1000ms内存限制65536 KB
题目描述
Facer今天买了n块蛋糕,不料被信息组中球球等好吃懒做的家伙发现了,没办法,只好浪费一点来填他们的嘴巴。他答应给每个人留一口,然后量了量每个人口的大小。Facer有把刀,可以切蛋糕,但他不能把两块蛋糕拼起来,但是他又不会给任何人两块蛋糕。现在问你,facer怎样切蛋糕,才能满足最多的人。(facer的刀很强,切的时候不会浪费蛋糕)。
输入格式
第一行n,facer有n个蛋糕。接下来n行,每行表示一个蛋糕的大小。再一行一个数m,为信息组的人数,然后m行,每行一个数,为一个人嘴的大小。(1≤n≤50,1≤m≤1024)
输出格式
一行,facer最多可以填多少张嘴巴。
输入样例
4
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30
输出样例
7
二分+贪心判断可行解,然后再用迭代加深搜索。此题难度较大,注意到数据的范围,蛋糕和嘴的大小会有很多的重复,需要进行一些优化。
AC代码:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=52;const int maxm=1025;const int INF=0x7f7f7f7f;int n,m,ans,tot;//蛋糕数,人数,最优解,蛋糕的总量 int tmp[maxn],cake[maxn],mouth[maxm],sum_mouth[maxm];bool dfs(int x,int last){    if(!x) return true;    if(tot<sum_mouth[x]) return false;    //剩下的蛋糕如果比未分配的x个人的嘴还要小是不可行的    tot-=mouth[x];    for(int i=x!=ans&&mouth[x]==mouth[x+1]?last:1;i<=n;i++)    //如果与上一个人嘴大小相同,那么上一个人若没有选前i块蛋糕这一个人也不用选    {        while(i<n&&cake[i]==cake[i+1]) i++;        //如果当前需要枚举的蛋糕与上一块蛋糕的大小相同只选最后的那块        if(cake[i]>=mouth[x])        {            cake[i]-=mouth[x];            if(cake[i]<mouth[1]) tot-=cake[i];            //如果剩下的蛋糕大小比第一个人的嘴还小那么就没用了//将所有没用的蛋糕和已经切好的蛋糕从总蛋糕大小中减去            if(dfs(x-1,i))            {                if(cake[i]<mouth[1]) tot+=cake[i];                cake[i]+=mouth[x];                   tot+=mouth[x];                return true;            }            if(cake[i]<mouth[1]) tot+=cake[i];            cake[i]+=mouth[x];        }    }    tot+=mouth[x];    return false;} bool check(int m){    int mincake,pos;    memcpy(tmp,cake,sizeof(cake));    //用贪心的方法每次选择符合条件的最小的蛋糕     for(int i=m;i;i--)    {        mincake=INF,pos=-1;        for(int j=1;j<=n;j++)        {            if(tmp[j]>=mouth[i]&&mincake>tmp[j]) mincake=tmp[j],pos=j;        }        if(pos<0) return false;        tmp[pos]-=mouth[i];    }    return true;} int main(){   scanf("%d",&n);    for(int i=1;i<=n;i++) {scanf("%d",&cake[i]);tot+=cake[i];}    scanf("%d",&m);    for(int i=1;i<=m;i++) {scanf("%d",&mouth[i]);}    sort(cake+1,cake+n+1);    sort(mouth+1,mouth+m+1);    for(int i=1;i<=m;i++) sum_mouth[i]=sum_mouth[i-1]+mouth[i];    int l=0,r=m,mid;    if(check(m))    {        printf("%d\n",m);        return 0;    }    while(l+1<r)    {        mid=(l+r)>>1;        if(check(mid)) l=mid;        else r=mid;    }    ans=r;    //得到一个近似最优解,在此基础上进行迭代加深搜索     while(dfs(ans,1)&&ans<=m) ans++;    printf("%d\n",ans-1);  }
D挑战大魔王的勇士 上机考试(2016)
时间限制1000ms内存限制65536 KB
题目描述
woem公主被邪恶的大魔王抓走了!为了拯救公主,国王紧急排出了一名的勇者去挑战大魔王。大魔王有n支护卫队,每支护卫队有k个恶魔。勇者和恶魔都有攻击力和防御力,当两者发生战斗时,若一方的防御力小于另一方的攻击力,那么这一方就会死亡(所以存在两者都死亡或都存活的情况)。勇者的攻击力为1,恶魔的防御力均为0。每当勇者击杀一只恶魔并存活时,勇者的防御力就会增加1。当勇者与一支护卫队战斗时,他会按照护卫队内的顺序依次与恶魔发生战斗(恶魔们训练有素,总是排成竖线攻击)。那么勇者的初始防御力为多少时,才可以打败这些护卫队,来到魔王面前拯救woem公主呢?勇者可以决定先与哪支护卫队发生战斗,但必须击杀完一支护卫队才能挑战另一支。
输入格式
第一行两个数字n和k依次表示护卫队的数量和队内恶魔的数量。接下来n行每行k个数,为每支护卫队里的恶魔的攻击力(勇者挑战这支队时,就按顺序依次挑战)。所有恶魔的攻击力≤106。对于前四组数组n=8,k=2;对于第五组数据n=8,k=3;对于第六组数据n=16,k=3;对于第七组数据n=16,k=2;对于第八组数据n=1000,k=2;对于第九组数据n=100000,k=2;
对于第十组数据n=100000,k=3。样例不包含在测试数据中。
输出格式
一个数,表示最小的初始防御力。
输入样例
2 2
3 4
1 2
输出样例
1
设一支护卫队中恶魔的攻击力分别为a1,a2,a3,……an,则勇士挑战它们时需要的防御力是a1,a2-1,a3-2,……an-n+1中的最大值。对于每一支护卫队都计算出这个最大值,按照贪心的思想,初始勇士的防御力就是这些最大值中的最小值,勇士按照它们最大值从小到大的顺序挑战护卫队。在挑战的过程中如果发现勇士的防御力不够了,就再从初始值中加进去。下面的我的代码通过了8组数据,最后两组数据TLE。
#include<cstdio>#include<iostream>#include<algorithm>using namespace std;int maxs[100010];int datas[100010][5]; int main(){    int n,k,ans=0,defense=0;    scanf("%d %d",&n,&k);    for(int i=0;i<n;i++)    {        for(int j=0;j<k;j++)        {            int temp;            scanf("%d",&temp);            datas[i][j]=temp-j;        }            maxs[i]=*max_element(datas[i],datas[i]+k);    }    int t=1000010,pos;    for(int i=0;i<n;i++)    {        if(maxs[i]<t)        {            t=maxs[i];            pos=i;        }    }    ans=t;    defense=ans+k;    maxs[pos]=-1;    while(1)    {        int flag=0;        for(int i=0;i<n;i++)        {            if(maxs[i]<=defense&&maxs[i]!=-1)            {                flag=1;                maxs[i]=-1;                defense+=k;            }        }        if(!flag) break;    }    while(*max_element(maxs,maxs+n)!=-1)    {        int t=1000010,pos;        for(int i=0;i<n;i++)        {            if(maxs[i]<t&&maxs[i]!=-1)            {                t=maxs[i];                pos=i;            }        }        ans+=t-defense;        defense+=t-defense+k;        maxs[pos]=-1;        while(1)        {            int flag=0;            for(int i=0;i<n;i++)            {                if(maxs[i]<=defense&&maxs[i]!=-1)                {                    flag=1;                    maxs[i]=-1;                    defense+=k;                }            }            if(!flag) break;        }          }    printf("%d\n",ans);}
                                             
0 0
原创粉丝点击