2017蓝桥杯c组

第一题

标题:贪吃蛇长度

±------------------------------------------------+
| |
| H###### #### |
| # # # |
| # # # |
| # #### # # |
| # # # # # |
| ######@### # # |
| # #### # # |
| # # # # # |
| ####@#######@### # # |
| # # # # # |
| T ##### # # # ## |
| # # ### ### ## |
| ################ # # #### |
| # # # # |
| ############## #######@########## |
| # ### |
| ########################### |
±------------------------------------------------+

小明在爷爷的私人收藏馆里找到一台老式电脑。居然没有图形界面,只能用控制台编程。

经过小明的一阵摸索,神奇地设计出了控制台上的贪食蛇游戏。

如上图,是游戏时画面截图。
其中,H表示蛇头,T表示蛇尾。#表示蛇的身体,@表示身体交叉重叠的地方。
你能说出现在的贪吃蛇长度是多少吗?

其实,只要数出#的数目算1,数出@的数目,算2,再加上头尾各算1就计算好了。

人工数一下?太累眼睛了,聪明的你为什么不让计算机帮忙呢?

本题的要求就是: 请填写上图中贪食蛇的长度是多少?

注意:需要提交的是一个整数,不要添加任何多余内容(比如说明或注释)
#include <iostream>
#include <bits/stdc++.h>
#include <stack>
#include <set>
#include <map>
using namespace std;
int main()
{
	int sum=0;
    for(int i=0;i<20;i++)
    {
        for(int j=0;j<51;j++)
        {
            char c;
            scanf("%c",&c);
            if(c=='#')sum++;
            if(c=='@')sum+=2;
        }
    }
    cout<<sum+2;
}

第二题

标题:兴趣小组

为丰富同学们的业余文化生活,某高校学生会创办了3个兴趣小组
(以下称A组,B组,C组)。
每个小组的学生名单分别在【A.txt】,【B.txt】和【C.txt】中。
每个文件中存储的是学生的学号。

由于工作需要,我们现在想知道:
既参加了A组,又参加了B组,但是没有参加C组的同学一共有多少人?

请你统计该数字并通过浏览器提交答案。

注意:答案是一个整数,不要提交任何多余的内容。


笨笨有话说:
哇塞!数字好多啊!一眼望过去就能发现相同的,好像没什么指望。
不过,可以排序啊,要是每个文件都是有序的,那就好多了。

歪歪有话说:
排什么序啊,这么几行数字对计算机不是太轻松了吗?
我看着需求怎么和中学学过的集合很像啊…

A:link
B:link
C:link


#include<bits/stdc++.h>
using namespace  std;
map<string,int>A;
map<string,int>B;
map<string,int>C;
int main()
{
    int sum=0,a=150,b=250,c=250;//数出来每个有多少个
    string s;
    while(a--)
    {
        cin>>s;
        A[s]=1;
    }
    while(b--)
    {
        cin>>s;
        B[s]=1;
    }
    while(c--)
    {
        cin>>s;
        C[s]=1;
    }
    for(map<string,int>::iterator it=A.begin();it!=A.end();it++)
        if(B.count((it->first))&&C.count(it->first)==0)
            sum++;
    cout<<sum<<endl;
    return 0;

}

笔记:文件读入,也可以直接算出数量直接输入题目用个set排除就可以了

第三题

标题:算式900

小明的作业本上有道思考题:

看下面的算式:

(□□□□-□□□□)*□□=900

其中的小方块代表09的数字,这10个方块刚好包含了09中的所有数字。
注意:0不能作为某个数字的首位。

小明经过几天的努力,终于做出了答案!如下:
(5012-4987)*36=900

用计算机搜索后,发现还有另外一个解,本题的任务就是:请你算出这另外的一个解。

注意:提交的格式需要与示例严格一致;
括号及运算符号不要用中文输入法;
整个算式中不能包含空格。

注意:机器评卷,不要填写任何多余的内容,比如说明文字。

笔记:next_permutation

#include<bits/stdc++.h>
using namespace  std;
int a[] = {0,1,2,3,4,5,6,7,8,9,10};
int main()
{
    do{
        if(a[0]==0||a[4]==0||a[8]==0)continue;
        int x1 = a[0]*1000+a[1]*100+a[2]*10+a[3];
        int x2 = a[4]*1000+a[5]*100+a[6]*10+a[7];
        int x3 = a[8]*10+a[9];
        if((x1-x2)*x3==900)printf("(%d-%d)*%d=900\n",x1,x2,x3);
    }while (next_permutation(a,a+10));
    return 0;

}

第四题

标题:承压计算

X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。

每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。

                         7 
                        5 8 
                       7 8 8 
                      9 2 7 2 
                     8 1 4 9 1 
                    8 1 8 8 4 1 
                   7 9 6 1 4 5 4 
                  5 6 5 5 6 9 5 6 
                 5 5 4 7 9 3 5 5 1 
                7 5 7 9 7 4 7 3 3 1 
               4 6 4 5 5 8 8 3 2 4 3 
              1 1 3 3 1 6 6 5 5 4 4 2 
             9 9 9 2 1 9 1 9 2 9 5 7 9 
            4 3 3 7 7 9 3 6 1 3 8 8 3 7 
           3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
          8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
         8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
        2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
       7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
      9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
     5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
    6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
   2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
  7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
 1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 

7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9
7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6
5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X

其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。

假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。

工作人员发现,其中读数最小的电子秤的示数为:2086458231

请你推算出:读数最大的电子秤的示数为多少?

注意:需要提交的是一个整数,不要填写任何多余的内容。


笨笨有话说:
不断的除2,加到下面,除2,加到下面,… 不会浮点精度溢出吧?
歪歪有话说:
怕除不开还不好办, 把每个数字扩大一定的倍数不就好了。
笔记: 认真读题是关键

#include<bits/stdc++.h>
using namespace  std;
typedef long long ll;
ll arr[30][30];
int main()
{
    ll factor =1;
    for(int i=0;i<30;i++)
    {
        factor<<=1;
    }
    for(int i=0;i<29;i++)
    {
        for(int j=0;j<=i;j++)
        {
            int a;
            scanf("%d",&a);
            arr[i][j]=a*factor;
        }
    }
    for(int i=0;i<29;++i)
    {
        for(int j=0;j<=i;++j)
        {
            ll temp = arr[i][j]/2;
            arr[i+1][j]+=temp;
            arr[i+1][j+1]+=temp;
        }
    }
    sort(arr[29],arr[29]+30);
    cout<<arr[29][29]/2;//这里是已经算出来位数大概就是2^29次方所以要/2
    return 0;
}

第五题

笔记:直接推,大胆猜想,小心论证
标题: 杨辉三角

杨辉三角也叫帕斯卡三角,在很多数量关系中可以看到,十分重要。

第0行: 1
第1行: 1 1
第2行: 1 2 1
第3行: 1 3 3 1
第4行: 1 4 6 4 1

两边的元素都是1, 中间的元素是左上角的元素与右上角的元素和。

我们约定,行号,列号都从0计数。
所以: 第6行的第2个元素是15,第3个元素是20

直观地看,需要开辟一个二维数组,其实一维数组也可以胜任。
如下程序就是用一维数组“腾挪”的解法。

// 杨辉三角的第row行,第col列
long long f(int row, int col){
if(row<2) return 1;
if(col== 0) return 1;
if(col==row) return 1;

long long a[1024];
a[0]=1;
a[1]=1;	
int p = 2;
int q;

while(p<=row){
	a[p] = 1;
	for( _________________ ) a[q] = a[q] + a[q-1]; //填空
	p++;
}

return a[col];

}

int main()
{
printf("%d\n", f(6,2));
printf("%d\n", f(6,3));
printf("%lld\n", f(40,20));
return 0;
}

请仔细分析源码,并完成划线部分缺少的代码。
注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。
q=p-1;q>=1;q–

最大公共子串

标题:最大公共子串

最大公共子串长度问题就是:
求两个串的所有子串中能够匹配上的最大长度是多少。

比如:“abcdkkk” 和 “baabcdadabc”,
可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。

下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。

请分析该解法的思路,并补全划线部分缺失的代码。

#include <stdio.h>
#include <string.h>

#define N 256
int f(const char* s1, const char* s2)
{
int a[N][N];
int len1 = strlen(s1);
int len2 = strlen(s2);
int i,j;
memset(a,0,sizeof(int)NN);
int max = 0;
for(i=1; i<=len1; i++){
for(j=1; j<=len2; j++){
if(s1[i-1]==s2[j-1]) {
a[i][j] = __________________________; //填空
if(a[i][j] > max) max = a[i][j];
}
}
}

return max;

}

int main()
{
printf("%d\n", f(“abcdkkk”, “baabcdadabc”));
return 0;
}

注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。
a[i-1][j-1]+1;

第七题

笔记: 需要读这两个动漫人物的话,有时候得救之道就在其中

标题: Excel地址

Excel单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,

当然Excel的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

本题目既是要求对输入的数字, 输出其对应的Excel地址表示方式。

例如,
输入:
26
则程序应该输出:
Z

再例如,
输入:
2054
则程序应该输出:
BZZ

我们约定,输入的整数范围[1,2147483647]

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。


笨笨有话说:
这有点像进制关系,又不完全是。好像末2位是以1当26,末3位是以1当26*26

歪歪有话说:
要是从字母序列转数字还好点,倒过来有点麻烦,不过计算机跑得快啊。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[254];
int main()
{
    ll n,i=0;
    cin>>n;
    while(n)
    {   
        if(n%26==0)
        {
            a[i++] = 26;
            n/=26;
            n--;
        }
        else{
            a[i++] = n%26;
            n/=26;
        }
    }
    for(int j=i-1;j>=0;--j)
    {
        cout<<(char)('A'+(a[j]-1));
    }
    return 0;
}

第八题

标题:九宫幻方

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2
3 5 7
8 1 6

有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入格式:
输入仅包含单组测试数据。
每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

输出格式:
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

样例输入
0 7 2
0 5 0
0 3 0

样例输出
6 7 2
1 5 9
8 3 4

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。


笨笨有话说:
我最喜欢这类题目了。既然九宫幻方一共也没有多少,我就不辞辛劳地一个一个写出来好了。
也不能太过分,好歹用个数组。

笔记:打表也要技术,奈何不会

#include <bits/stdc++.h>
using namespace std;
int map_[10][10], sum,copy_[10][10],num;
bool vis[10];
bool check()
{
    int sum1 = (map_[0][0] + map_[0][1] + map_[0][2]);
    if (sum1 == (map_[1][0] + map_[1][1] + map_[1][2]) && sum1 == (map_[2][0] + map_[2][1] + map_[2][2]) && sum1 == (map_[0][0] + map_[1][0] + map_[2][0]) && sum1 == (map_[0][1] + map_[1][1] + map_[2][1]) && sum1 == (map_[0][2] + map_[1][2] + map_[2][2]) && sum1 == (map_[0][0] + map_[1][1] + map_[2][2]) && sum1 == (map_[0][2] + map_[1][1] + map_[2][0]))
        return true;
    return false;
}
void print(const int i[][10])
{
    for (int i1 = 0; i1 < 3; i1++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << i[i1][j]<<" ";
        }
        cout<<endl;
    }
}
void dfs(int step)
{
    if (step==10)
    {
        if (check())
        {
            for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
			    copy_[i][j]=map_[i][j];
            sum++;
            return;
        }
        return;
    }
    for (int i1=0; i1 < 3; i1++)
    {
        for (int j1=0; j1 < 3; j1++)
        {
            if (!map_[i1][j1])
            {
                for (int k = 1; k < 10; k++)
                {
                    if (!vis[k])
                    {
                        vis[k] = true;
                        map_[i1][j1] = k;
                        dfs(step+1);
                        map_[i1][j1] = 0;
                        vis[k] = false;
                        
                    }
                }
                return ;
            }
        }
    }
}
int main()
{
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cin >> map_[i][j];
            if (map_[i][j])
            {
                vis[map_[i][j]] = true;
                num++;
            }
                
        }
    }
    dfs(num+1);
    if (sum == 1)
        print(copy_);
    else
        cout << "Too many"<<endl;
    return 0;
}

第九题

标题:拉马车

小的时候,你玩过纸牌游戏吗?
有一种叫做“拉马车”的游戏,规则很简单,却很吸引小朋友。

其规则简述如下:
假设参加游戏的小朋友是A和B,游戏开始的时候,他们得到的随机的纸牌序列如下:
A方:[K, 8, X, K, A, 2, A, 9, 5, A]
B方:[2, 7, K, 5, J, 5, Q, 6, K, 4]

其中的X表示“10”,我们忽略了纸牌的花色。

从A方开始,A、B双方轮流出牌。

当轮到某一方出牌时,他从自己的纸牌队列的头部拿走一张,放到桌上,并且压在最上面一张纸牌上(如果有的话)。

此例中,游戏过程:
A出K,B出2,A出8,B出7,A出X,此时桌上的序列为:

K,2,8,7,X

当轮到B出牌时,他的牌K与桌上的纸牌序列中的K相同,则把包括K在内的以及两个K之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。
此时,A、B双方的手里牌为:
A方:[K, A, 2, A, 9, 5, A]
B方:[5, J, 5, Q, 6, K, 4, K, X, 7, 8, 2, K]

赢牌的一方继续出牌。也就是B接着出5,A出K,B出J,A出A,B出5,又赢牌了。
5,K,J,A,5
此时双方手里牌:
A方:[2, A, 9, 5, A]
B方:[Q, 6, K, 4, K, X, 7, 8, 2, K, 5, A, J, K, 5]

注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。

当某一方出掉手里最后一张牌,但无法从桌面上赢取牌时,游戏立即结束。

对于本例的初始手牌情况下,最后A会输掉,而B最后的手里牌为:

9K2A62KAX58K57KJ5

本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出-1。

输入为2行,2个串,分别表示A、B双方初始手里的牌序列。
输出为1行,1个串,表示A先出牌,最后赢的一方手里的牌序。

例如,
输入:
96J5A898QA
6278A7Q973

则程序应该输出:
2J9A7QA6Q6889977

再比如,
输入:
25663K6X7448
J88A5KJXX45A

则程序应该输出:
6KAJ458KXAX885XJ645

我们约定,输入的串的长度不超过30

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。


笨笨有话说:
不断删除前边的,又要后边添加… 如果用数组,需要开一个大点的,请佛祖保佑在游戏结束前,不会用到数组的边缘。

歪歪有话说:
反正串也不长,不如每次操作都返回一个新的串。

默默有话说:
我一般都不吱声,这是典型的队列结构,动态数组最好,没有?自己造一个呗!

笔记:模拟也要变一下方向更好进行操作

#include <bits/stdc++.h>
using namespace std;
string A, B, C;
bool op(string &x, string &z)
{
    if (x.length() == 0)
        return false;
    bool ans = true;
    char front = x[0];
    long i = z.find(front);
    if (i != string::npos) //桌上有这张牌
    {
        //将这牌插入x的尾部,并且将桌上0~i之间的牌依次插入x的尾部
        x.insert(x.end(), front);
        for (int j = 0; j <= i; ++j)
        {
            x.insert(x.end(), z[j]);
        }
        z.erase(0, i + 1); //从桌面上移除这些牌
    }
    else
    { //将这张牌入在面上(下标为0)
        z.insert(z.begin(), front);
        ans = false;
    }
    x.erase(x.begin());
    return ans;
}
int main()
{
    cin >> A >> B;
    bool flageA = true;
    bool flageB = false;
    while (1)
    {
        if (flageA)
        {
            flageA = op(A, C);
            if (A.length() == 0)
            {
                cout << B << endl;
                break;
            }
            flageB = !flageA;
        }
        if (flageB)
        {
            flageB = op(B, C);
            if (B.length() == 0)
            {
                cout << A << endl;
                break;
            }
            flageA = !flageB;
        }
    }
    return 0;
}

第十题

笔记: 想不出来尽量拿穷举拿分,至少可以过30%样例
标题:图形排版

小明需要在一篇文档中加入 N 张图片,其中第 i 张图片的宽度是 Wi,高度是 Hi。  

假设纸张的宽度是 M,小明使用的文档编辑工具会用以下方式对图片进行自动排版:

1. 该工具会按照图片顺序,在宽度 M 以内,将尽可能多的图片排在一行。该行的高度是行内最高的图片的高度。例如在 M=10 的纸张上依次打印 3x4, 2x2, 3x3 三张图片,则效果如下图所示,这一行高度为4。(分割线以上为列标尺,分割线以下为排版区域;数字组成的矩形为第x张图片占用的版面)

0123456789

111
111 333
11122333
11122333

2. 如果当前行剩余宽度大于0,并且小于下一张图片,则下一张图片会按比例缩放到宽度为当前行剩余宽度(高度向上取整),然后放入当前行。例如再放入一张4x9的图片,由于剩余宽度是2,这张图片会被压缩到2x5,再被放入第一行的末尾。此时该行高度为5:

0123456789

    44

111 44
111 33344
1112233344
1112233344

3. 如果当前行剩余宽度为0,该工具会从下一行开始继续对剩余的图片进行排版,直到所有图片都处理完毕。此时所有行的总高度和就是这 N 张图片的排版高度。例如再放入11x1, 5x5, 3x4 的图片后,效果如下图所示,总高度为11:

0123456789

    44

111 44
111 33344
1112233344
1112233344
5555555555
66666
66666777
66666777
66666777
66666777

现在由于排版高度过高,图片的先后顺序也不能改变,小明只好从 N 张图片中选择一张删除掉以降低总高度。他希望剩余N-1张图片按原顺序的排版高度最低,你能求出最低高度是多少么?

输入:
第一行包含两个整数 M 和 N,分别表示纸张宽度和图片的数量。
接下来 N 行,每行2个整数Wi, Hi,表示第 i 个图大小为 Wi*Hi。

对于30%的数据,满足1<=N<=1000
对于100%的数据,满足1<=N<=100000,1<=M, Wi, Hi<=100

输出:
一个整数,表示在删除掉某一张图片之后,排版高度最少能是多少。

样例输入:
4 3
2 2
2 3
2 2

样例输出:
2

另一个示例,
样例输入:
2 10
4 4
4 3
1 3
4 5
2 1
2 3
5 4
5 3
1 5
2 4

样例输出:
17

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

#include<iostream>
#include<cstring> 
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
//倒序预处理一个数组f,f(i)表示i号及其后的图片另起一行插入得到的高度
//然后按顺序枚举哪一张图片不选同时将选的图片插入
#define MAXN 100005
int M,N;
struct pic{
	int w,h;
}pics[MAXN];
int f[MAXN];
struct line{
	int w,h;
	line(){w=0,h=0;}
	line(int _w,int _h)
	{
		w = _w,h = _h;
	}
	line operator+(pic _p )
	{
		if(w+_p.w>M)//对其进行压缩
		{
			_p.h = ceil(1.0*_p.h*(M-w)/_p.w);
			_p.w = M - w;
		}
		return line(w+_p.w,max(h,_p.h));
	}
	bool full()
	{
		return w ==M;
	}
	void clr()
	{
		w=h=0;
	}
};
int push_till_full(line a,int k)
{
	for(;k<=N&&!a.full();++k)
	{
		a=a+pics[k];
	}
	return a.h+f[k];
}
int main()
{
    scanf("%d%d",&M,&N);
	for(int i=1;i<=N;i++)
	{
		scanf("%d%d",&pics[i].w,&pics[i].h);
	}
	for(int i=N;i>=1;--i)
	{
		f[i] = push_till_full(line(0,0),i);//f[i]指的是i号图片及其后面的图片另起一行插入得到的高度
	}
	line a;//开始没有宽度和高度
	int ans = 1e7;
	int per = 0;//记录之前完整累计的高度
	for(int i=1;i<=N;++i)
	{//不要第i第pic
		ans = min(ans,per+push_till_full(a,i+1));//用第i+1张图填充这个line
		a = a+pics[i];//将第i第图放入,作为下次迭代的line
		if(a.full())//行已经填满,重置line并且结算一个整行的高度
		{
			per+=a.h;
			a.clr();//开始一个新行
		}
	}
	cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值