第一次算法实验报告
学生姓名:汪涛 学号:U201014390
POJ 1017
1) 题目描述:
给你一组6种箱子的个数,问最少能够用多少个箱子把给出的一组6种箱子装起来,
输出最少箱子的个数。
2) 解题分析:
由于要使得箱子数最少,所以尽量选择大的箱子来装。
运用贪心。
3) 算法设计:
6*6的放满整个盒子,
5*5的还可以放11个1*1。
4*4的还可以放5个2*2的。
3*3的总个数模4后,也就是说最后一个盒子放几个3*3的。
如果是1,还可以放5个2*2和7个1*1。
如果是2,可以放3个2*2和6个1*1。
如果是3,可以放1个2*2和5个1*1的。
2*2的模9就是最后一个箱子里放2*2的个数,36-(2*2的个数%9)就是可以放1*1
个数。
最后(1*1的个数+35)/36就是最后的盒子数。
由于只涉及到常数运算,算法时间复杂度为O(1)。
4) 程序代码:
#include "stdio.h"
#include "string.h"
int a[7];
int res[7];
int main()
{
int sum_num ;
while(scanf("%d%d%d%d%d%d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6]))
{
sum_num = 0;
memset(res,0,sizeof(res));
if( a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0 && a[5] == 0 && a[6] == 0 )
break;
if( a[6] != 0 )
sum_num += a[6];
if( a[5] != 0 )
{
sum_num += a[5];
res[1] += 11*a[5];
}
if( a[4] != 0 )
{
sum_num += a[4];
res[2] += 5*a[4];
}
if(a[3] != 0)
{
sum_num += (a[3]+3)/4; //4个3*3才占用一个6*6
res[3] += 4-a[3]%4; //剩余多少3*3
if(res[3] == 1) //根据3*3的个数推出2*2,1*1的个数
{
++res[2];
res[1] += 5;
}
else if(res[3] == 2)
{
res[2] += 3;
res[1] += 6;
}
else if(res[3] == 3)
{
res[2] += 5;
res[1] += 7;
}
}
if(a[2]!=0)
{
if(a[2] >= res[2]) //先填剩下的2*2的
{
a[2] -= res[2];
res[2] = 0;
}
else
{
res[2] -= a[2];
res[1] += res[2]*4; //将剩余2*2转换为1*1的个数
a[2] = 0;
}
if(a[2] > 0) //如果还是不够,则找新的6*6来填充
{
sum_num += (a[2]+8)/9; //需要多少个6*6的
res[1] += (9-a[2]%9)*4; //剩下多少个1*1的
}
}
if(a[1] != 0)
{
if(a[1] >= res[1])
{
a[1] -= res[1];
}
else
{
a[1] = 0;
}
sum_num += (a[1]+35)/36; //需要多少个6*6的
}
printf("%d\n",sum_num);
}
return 0;
}
5) 实验结果及其分析:
1.
2.
3.结果与想法完全符合
6)实验心得:
由于poj1017这个题目是求一个最优值,所以本次实验采用了贪心的算法思想,用最大的箱子去装物品,剩余空间去容纳小的物品,就是这个贪心的思想。
POJ2376
1) 题目描述
农场要做清洁,一个时间段里面至少要有一条牛在工作,要使整个时间段都有牛在工作,求牛的最小数量。
2) 解题分析
可以将需要工作的实践段看作一个线段,每一个牛的工作时间段也看作线段,整个题目就可以转变成求线段的最小覆盖。
3) 算法设计
对牛的工作时间段进行左边由小到大的排序,然后在选择的区域内选择向右延伸最远的,测试完n个牛的数据之后如果不能比t大,则输出-1。
4) 程序代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef struct //题目的大意就是求线段的最小覆盖
{
int l , r; //把牛工作的时间当作线段来处理
}line;
line cow[25005];
int n , t;
int cmp(const line &a , const line &b)
{
return a.l < b.l;
}
int main()
{
while(scanf("%d%d",&n,&t) != EOF)
{
for(int i = 0 ; i < n ; i++)
scanf("%d%d",&cow[i].l,&cow[i].r);
sort(cow,cow+n,cmp);
int count = 0;
int left = cow[0].l , right = cow[0].r;
if(left > 1) //最左边的都比1大 那么显然不能覆盖
{
printf("-1\n");
continue;
}
int i = 0 , temp_r , ri = 0;
int flag = 1;
while(ri < t && i < n)
{
int find = 0;
temp_r = 0;
while(cow[i].l <= ri+1 && i < n)
{
find = 1;
if(cow[i].r > temp_r)
temp_r = cow[i].r;
i++;
}
if(!find)
{
flag = 0;
break;
}
ri = temp_r;
count++;
}
if(!flag || ri < t)
printf("-1\n");
else
printf("%d\n",count);
}
return 0;
}
5) 实验结果及其分析
1.
2.
3.时间复杂度
计算的复杂度主要在排序O(nlogn)和扫过去的循环O(n)
6) 实验心得
用贪心的思想解决了线段最小覆盖问题。