7.13
要点:贪心算法
note:分成子问题,分别求最优解
找规律->得猜想->证猜想->写代码
例题:hdu2037、hdu2021、nyoj891
常用技巧: 0.sort函数的使用
1.sort自定义排序规则sort(,,cmp)
2.结构体排序
思考题:
nyoj1170
描述
小明和小红在打赌说自己数学学的好,于是小花就给他们出题了,考考他们谁NB,题目是这样的给你N个数
在这n个数之间添加N-1个*或+,使结果最大,但不可以打乱原顺序,请得出这个结果
如
1 3 5
结果是(1+3)*5=20;最大
可以添加若干个括号,但一定要保证配对,但是每两个数之间只可能有一个*或+
数列最前和最后不应有+或乘
小明想赢小红但是他比较笨,请你帮帮他
输入
多组测试数据以EOF结束,每组有一个n(n<10000),然后有n个正整数a[i](1<=a[i]<=20)
输出
输出最大的结果由于结果比较大,结果对10086取余
练习
A题 发工资咯:)
note:好久没做过这种输入0就结束程序的了,还以为每个样例以0结束my god…MARK一下
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[10005];
bool cmp(int a,int b) //sort大到小排
{
return a>b;
}
int main()
{
int n;
int c[6]={100,50,10,5,2,1};
while(scanf("%d",&n)!=EOF&&n) //0结束
{
memset(a,0,sizeof(a));
int i,j;
int count=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(!a[i])
break;
}
sort(a,a+n,cmp); //可以不要排序,没多大意义
for(i=0;i<n;i++)
for(j=0;j<6;j++)
{
if(c[j]>a[i])
continue;
else if(c[j]==a[i])
{
count++;
break;
}
else
{
int t;
t=a[i]/c[j];
count+=t;
a[i]=a[i]%c[j];
}
}
printf("%d\n",count);
}
return 0;
}
============================我是分割线===============================
C题 Crossing River
**
note:多找找规律
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int i,n,t;
scanf("%d",&t);
while(t--)
{
int time=0,a[1000];
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
//time=a[0]+a[1]+a[n-1];
while(n>=4)
{
int t1,t2;
t1=a[0]+a[1]*2+a[n-1]; //两个最慢的走
t2=a[n-1]+a[n-2]+a[0]*2; //最快的来回带慢的飞~
time+=min(t1,t2); //比较取时间少的方案
n-=2;
}
if(n==3)
time+=a[0]+a[1]+a[2];
else if(n==2)
time+=a[1];
else if(n==1)
time+=a[0];
printf("%d\n",time);
}
return 0;
}
D题 今年暑假不AC
note:结构体排序,真的很好用!按结束时间升序
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct temp
{
int a,b;
};
typedef struct temp T;
bool cmp(T m,T n)
{
return m.b<n.b;
}
int main()
{
int n,i,j;
while(scanf("%d",&n)!=EOF&&n)
{
T f[1000];
int count=1;
for(i=0;i<n;i++)
{
scanf("%d %d",&f[i].a,&f[i].b);
}
sort(f,f+n,cmp);
for(i=1,j=0;i<n;i++)
if(f[i].a>=f[j].b)
{
j=i;
count++;
}
printf("%d\n",count);
}
return 0;
}
============================我是分割线===============================
E题 Hero
**
note:这题跟基友讨论了很久,终于理解透彻了!
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct temp
{
double dp,hp; /*这里用double,是为了下面(*)式子中的除法能比较出高下,否则31/3和20/2是一样的*/
};
typedef struct temp T;
bool cmp(T m,T n)
{
/*double d1,d2; //如果上面用int,这里就不能去掉,下面改成return d1>d2;
d1=1.0*m.dp/m.hp;
d2=1.0*n.dp/n.hp;*/ //(*)
return (m.dp/m.hp)>(n.dp/n.hp); //(**)
/*原来WA是因为上面(*)虽然注释掉,但是作用没发挥出来,结构体那里又用了int,导致排序出问题
dps/hp来计算敌人的威胁程度是因为我联想到初高中的时候,我参加铅球比赛,我几乎是成绩是排3,然而我的体重几乎是全场最轻,就是说用 距离/体重 来算成绩的话,我肯定就是第一了...*/
}
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF)
{
T f[1000];
int attack=0;
int loss=0;
for(i=0;i<n;i++)
{
scanf("%lf %lf",&f[i].hp,&f[i].dp);
attack+=f[i].dp;
}
sort(f,f+n,cmp);
for(i=0;i<n;i++)
{
loss+=attack*f[i].hp;
attack-=f[i].dp;
}
printf("%d\n",loss);
}
return 0;
}
============================我是分割线===============================
F题 Subsequence
**
note:用到记忆化的思想,节省时间
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100005];
int sum[100005];
int main()
{
int n,s,i,j,t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&s);
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
int ans=n+1;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i-1]; //名副其实的前i项,就是sum[0]==0;
}
int j=1;
int tag=1;
if(a[0]>=s) ans=1;
else if(sum[n]<s); //打分号,不作处理~一开始就看总和是否大于s
//ans=n+1;
else{
for(i=1;i<=n;i++) /*虽然这里是二层循环,但是时间复杂度只是第一层的线性关系,并不是 指数关系,因为第二层循环的j实际上是跟第一层的i是并驱的,sum[j]-sum[i-1]一旦大于s,j就停下来等i*/
{
for(;sum[j]-sum[i-1]<s;)
{
if(j==n)
tag=0;
j++;
}
if(j<=n&&sum[j]-sum[i-1]>=s)
ans=min(ans,j-i+1); //取范围最小值
if(!tag)
break;
}
}
if(ans<=n)
printf("%d\n",ans);
else
printf("0\n");
}
return 0;
}
对F题的循环用表格举例子描述一下:如输入n=10,s=15 5 6 7 10
i | j | 第i个数到第j个数的和 | 大于s时区间长度 |
---|---|---|---|
1 | 1 | 5<(s=15)(不能直接打5小于s,好奇怪…) | |
1 | 2(j往右跑) | 11<(s=15) | |
1 | 3(j往右跑) | 18>=(s=15) | 3 |
2(i往右跑) | 3 | 13<(s=15) | |
2 | 4(j往右跑) | 23>=(s=15) | 3 |
3(i往右跑) | 4 | 17>=(s=15) | 2 |
*由此可见时间复杂度只是n的线性关系O(n)
贪心算法感觉学得不是很好,我是不是不怎么贪心啊(逃
过题排前几的都是贪心鬼!(捂脸