第一题理解起来应该不难,就是个累加过程。每次要从小的开始累加,才能保证累加和最小。
所以我们第一步把输入的数组排好序,按次序累加即可
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
int a[10005];
int main()
{
int n;
scanf("%d",&n);
while(n--){
int m;
scanf("%d",&m);
for(int i=0;i<m;i++) scanf("%d",&a[i]);
sort(a,a+m);
int m1=m-1,flag=0,j=0,sum=0;
while(m1--){
sum = a[j]+a[j+1];
a[j+1] =sum;
flag+=sum;
j++;
}
printf("%d\n",flag);
}
return 0;
}
经典的区间dp,详情可以见紫书p232
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
struct node
{
int start,endding;
}stu[105];
bool cmp(node a,node b){
if(a.endding!=b.endding)
return b.endding>a.endding;
else{
}
}
int main()
{
int n,cot = 1;;
while(~scanf("%d",&n)){
if(n==0) return 0;
for(int i=0;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
stu[i].start=a;
stu[i].endding=b;
}
sort(stu,stu+n,cmp);
cot = 1;
node p=stu[0];
for(int i=0;i<n-1;i++){
if(p.endding<=stu[i+1].start) cot++,p=stu[i+1];
//printf("%d--%d\n",stu[i].start,stu[i].endding);
}
printf("%d\n",cot);
}
return 0;
}
C:
贪心策略可以很简单的看出来,就是样例的 Javabeen/catfood 最大的先选,此时才是换取Javabeen最大的数量
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
struct node
{
int fa;
int j;
double cot;
}rom[1005];
bool cmp(node a,node b)
{
return a.cot>b.cot;
}
int main()
{
int n;
double sumfa;
while(~scanf("%lf%d",&sumfa,&n))
{
if(sumfa==n&&n==-1) return 0;
int i;
for(i=0;i<n;i++){
scanf("%d%d",&rom[i].j,&rom[i].fa);
rom[i].cot=(rom[i].j*1.0/rom[i].fa);
}
sort(rom,rom+n,cmp);
double sum=0;
for(i=0;i<n;i++){
if(sumfa>=rom[i].fa){
sumfa-=rom[i].fa;
sum+=rom[i].j;
}
else{
if(sumfa>=0)
sum+=rom[i].j*1.0*sumfa/rom[i].fa;
break;
}
}
printf("%.3lf\n",sum);
}
return 0;
}
D:
这一题的策略需要细想,题目要求是要扣分越少越好,并不是做完的作业越多越好。所以我们贪心的策略的就是把分值高的排在前面先完成,分值相同的,截止日期小的排前面。
这样一来就会有一个问题,我们假如说有 1---1和2---7 这两门课 我们排好序后的顺序为 2---7&1---1,我们先完成的第二天完成的作业,到第二天就不能完成第一天的作业了。所以我们从后往前来推时间,这样可以避免这种问题。
还有一点就是要标记当天,不标记的话可能导致这一天完成多次作业。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int day;
int score;
}a[10005];
int vis[10005];
int cmp(node a,node b)
{
if(a.score!=b.score)
return a.score>b.score;
else return a.day<b.day;
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int m;
scanf("%d",&m);
memset(vis,0,sizeof(vis));
int i,j;
for(i=0;i<m;i++) scanf("%d",&a[i].day);
for(i=0;i<m;i++) scanf("%d",&a[i].score);
sort(a,a+m,cmp);
int sum=0;
for(i=0;i<m;++i)//这两层for循环是关键
{
j=a[i].day;
for(;j>=1;--j)//标记哪天已经完成了作业
{
if(!vis[j])//没有作业的时候就标记,有作业就往前推 --j
{
vis[j]=1;
break;
}
}
if(j==0)
sum+=a[i].score;
}
printf("%d\n",sum);
}
return 0;
}