B4093 [CSP-X2021 山东] 发送快递

题目背景

原题为错题,不可做。数据范围修改如下,请以题目背景中的为准:

【数据范围和限制】

对于 40%40\%40% 的数据,1≤n≤231 \leq n \leq 231n231≤ai≤1001 \leq a_i \leq 1001ai100s=0s=0s=0mmm 的值保证有解。

对于 100%100\%100% 的数据,1≤n≤231 \leq n \leq 231n231≤ai≤1001 \leq a_i \leq 1001ai1000≤s≤150 \leq s \leq 150s15mmm 的值保证有解。

为了防止无意义的钻牛角尖的 hack,本题认为 mmm 不超过 231−12^{31}-12311

题目描述

小华有 nnn 本不同的书(编号为 1,2,3,…,n1,2,3,\dots,n1,2,3,,n),重量分别是 a1,a2,…,ana_1,a_2,\dots,a_na1,a2,,an 公斤(重量可以相同)。他想把这些书以快递的方式发给自己的好朋友,要求每个包裹的重量不能超过 mmm 公斤(可以等于 mmm 公斤),并且小华想把其中一些书(一组书,用书的编号给出来)放在一个包裹里,应该如何打包才能使得快递件数最少。

输入格式

第一行,包含两个整数 n,mn,mn,m,之间用一个空格隔开,分别表示书的数量和快递包裹的最大重量。

第二行 nnn 个整数 aia_iai,表示 nnn 本书的重量,每两个整数之间用一个空格隔开。

第三行一个整数 sss,表示一共有 sss 组书(每组书需要打包在一起)。如果 s=0s=0s=0,则无此限制。数据保证每组书的重量不超过 mmm

第四行开始共 sss 行,每行若干个整数,表示必须放在一个包裹里的书的编号,每两个整数之间用一个空格隔开。

输出格式

输出文件一行,一个整数,即快递最少件数。

输入输出样例 #1

输入 #1

5 10
8 4 8 2 5
0

输出 #1

3

输入输出样例 #2

输入 #2

10 80
49 11 44 18 28 24 19 10 27 29
2
1 5
4 8 2

输出 #2

4

说明/提示

【输入输出样例 1 说明】

111 本和第 444 本打包,重量是 101010 公斤。第 222 本和第 555 本打包,重量是 999 公斤。第 333 本单独打包,重量是 888 公斤。所以一共 333 件快递。

【输入输出样例 2 说明】

111 本和第 555 本打包,第 222 本、第 444 本、第 888 本和第 101010 本打包,第 333 本和第 777 本打包,第 666 本和第 999 本打包。所以一共 444 件快递。

【数据范围和限制】

对于 40%40\%40% 的数据,1≤n≤1051 \leq n \leq 10^51n1051≤ai≤1001 \leq a_i \leq 1001ai100s=0s=0s=0mmm 的值保证有解。

对于 100%100\%100% 的数据,1≤n≤1051 \leq n \leq 10^51n1051≤ai≤1001 \leq a_i \leq 1001ai1000≤s≤1000 \leq s \leq 1000s100mmm 的值保证有解。

C++实现

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,s,ans=54,c[55],b[55],a[55],r,lst,p,k;
vector<int> G[55];
bool vis[55];
void build(int now){
    vis[now]=1;
    a[p]+=b[now];
    for(int i:G[now]){
        if(!vis[i]) build(i);
    }
}
bool cmp(int a,int b){
    return a>b;
}
void dfs(int now,int val){
    if(val>=ans) return;
    if(now==p+1){
        ans=val;
        return ;
    }
    for(int i=1;i<=k;i++){
        if(c[i]+a[now]<=m){
            c[i]+=a[now];
            dfs(now+1,val);
            c[i]-=a[now];
        }
    }
    k++;
    c[k]+=a[now];
    dfs(now+1,val+1);
    c[k]-=a[now];
    k--;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>b[i];
    }
    cin>>s;
    for(int i=1;i<=s;i++){
        cin>>lst;
        while(cin>>r){
            G[lst].push_back(r);
            G[r].push_back(lst);
            lst=r;
            if(cin.get()=='\n') break;
        }
    }
    for(int i=1;i<=n;i++) if(!vis[i]) p++,build(i);
    sort(a+1,a+1+p,cmp);
    dfs(1,0);
    cout<<ans;
    return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐