2198: 小P当志愿者送餐

题目描述
在ICPC程序设计大赛期间,小P作为志愿者的任务是给各个学校送盒饭,小P一次最多可以携带M份盒饭。总共有N个学校来参加比赛,这N个学校的休息点在一条笔直的马路边一字排开,路的一头是小P取盒饭的地方,假设为原点,每两个相邻点之间,小明需要行走15秒,包括从原点到第一个休息点,交付一份盒饭需要3秒时间。从第一个休息点到第N个休息点需要的盒饭数分别为 a1, a2, a3..., an。 问小P最短需要多少时间把全部盒饭送完并回到原点。 
输入
第一行输入一个正整数T,表示有T组测试数据,每组占两行,第一行两个整数M、N(0<M,N<50),第二行输入N个整数a1  a2  a3 ...an (0<=a1....an<50) 
输出
每行输出一个整数,对应一组测试数据,表示小P送完全部盒饭并返回原点的总时间(秒)。  
样例输入 Copy
2
18 2
8 6
10 3
5 0 8
样例输出	Copy
102
159
提示
消耗的时间最少只由走的路程最短决定,每一趟来回走的路程是这一次送餐的最远的点距离原点的两倍。

我的错误:

//M份盒饭。  总共有N个学校来参加比赛
//每两个相邻点之间,小明需要行走15秒
//交付一份盒饭需要3秒时间
//102=15*(n*2)+(A1+A2+An)*3
//a1 a2 a3 a4 
#include<iostream>
using namespace std;
int main()

{
    int t,n,sum=0,book,a,b,i,j;//book表示手里拿的东西 t表示时间 
    cin>>n;//几组数据 
    while(n--){ 
        cin>>a>>b;
        int arr[b];
        book=a;
        t=0; 
        sum=0;
        for( i=0;i<b;i++) {
        cin>>arr[i];
        sum+=arr[i];}
        
        for(j=b-1;j>=0;j--){
            book=book-arr[j];
            while(book<=0){
                if(i==0&&book==0) break;
                t+=(j+1)*15*2;
                book=book+a;
            }
        }
        t=t+b*15*2+sum*3;
        cout<<t<<endl;
    } 
    
}
View Code

错误分析主要是送最远的饭的目标寻找没考虑,考虑后正确

//M份盒饭。  总共有N个学校来参加比赛
//每两个相邻点之间,小明需要行走15秒
//交付一份盒饭需要3秒时间
//102=15*(n*2)+(A1+A2+An)*3
//a1 a2 a3 a4 
#include<iostream>
using namespace std;
int main()

{
    int t,n,sum=0,book,a,b,i,j,q;//book表示手里拿的东西 t表示时间 
    cin>>n;//几组数据 
    while(n--){ 
        cin>>a>>b;
        int arr[b];
        book=a;
        t=0; 
        sum=0;
        for( i=0;i<b;i++) {
        cin>>arr[i];
        sum+=arr[i];
        if(arr[i]>0) q=i; 
        }
        
        for(j=q;j>=0;j--){
            book=book-arr[j];
            while(book<0){
                t+=(j+1)*15*2;
                book=book+a;
            }
        }
        t=t+(q+1)*15*2+sum*3;
        cout<<t<<endl;
    } 
    
}
View Code

同学用的贪心算法:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 100;
int a[N];

int main()
{
#ifdef LOCAL
    freopen("C:/input.txt", "r", stdin);
#endif
    int T;
    cin >> T;
    while (T--)
    {
        int m, n, p = 0; //p最后一个有效点
        scanf("%d%d", &m, &n);
        ll ans = 0;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &a[i]);
            if (a[i])
                p = i;
        }
        while (p)
        {
            ans += p * 30; //到p再回原点代价
            int t = m; //身上所带物品
            while (p && t)
            {
                int e = min(t, a[p]); //交付
                t -= e;
                a[p] -= e;
                ans += e * 3; //交付代价
                while (p && !a[p]) //如果当前点已经送完则移动p
                    p--;
            }
        }
        printf("%lld
", ans);
    }

    return 0;
}
View Code

 分析:

1.从远往近送,

2.确定的最远点需要送餐,arr[i]>0

3.贪心问题,e=min(arr[j],book),很重要

自己实现,差不多,

//M份盒饭。  总共有N个学校来参加比赛
//每两个相邻点之间,小明需要行走15秒
//交付一份盒饭需要3秒时间
//102=15*(n*2)+(A1+A2+An)*3
//a1 a2 a3 a4 
#include<iostream>
using namespace std;
int main()

{
    int t,n,sum=0,book,a,b,i,j,p,e;//book表示手里拿的东西 t表示时间 
    cin>>n;//几组数据 
    while(n--){ 
        cin>>a>>b;
        int arr[b];
        book=a;
        t=0; 
        sum=0;
        for( i=0;i<b;i++) {
        cin>>arr[i];
        sum+=arr[i];
        if(arr[i])  p=i;
        }
        
        for(j=p;j>=0;j--){
            e=min(arr[j],book);
            book-=e;
            arr[j]-=e;
            while(arr[j]>0){
                t+=(j+1)*15*2;
                book=a;
                e=min(arr[j],book);
                book-=e;
                arr[j]-=e;
            }
        }
        t=t+(p+1)*15*2+sum*3;
        cout<<t<<endl;
    } 
    
}
View Code
原文地址:https://www.cnblogs.com/helloworld2019/p/10468041.html