欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

泉五培训Day4

程序员文章站 2022-11-10 15:06:31
T1 收果子 题目 【题目描述】 有一个果园,有n棵果树依次排成一排,其中已知第 i 棵果树上结了ai个果子。现在要按照果树编号顺序依次收果子,对于一个能装v个果树的果篮,收果子从第1棵果树开始,如果果篮的剩余容积大于等于当前果树所结的果子,那么就可以将此树上的果子全收下来,否则就要拿一个新的篮子来 ......

t1 收果子

题目

【题目描述】

    有一个果园,有n棵果树依次排成一排,其中已知第 i 棵果树上结了ai个果子。现在要按照果树编号顺序依次收果子,对于一个能装v个果树的果篮,收果子从第1棵果树开始,如果果篮的剩余容积大于等于当前果树所结的果子,那么就可以将此树上的果子全收下来,否则就要拿一个新的篮子来装果子。特别地,如果果篮容积小于某果树的结果数,那么我们认为这样将永远不能收完果子。

    现在假若只能用k个果篮,问按照以上方法能使用不超过k个果篮并收完所有果子的果篮最小容积。

【输入格式】

    输入有两行,第一行两个正整数,代表 n、k,意义如题。

    第二行 n 个正整数ai,代表每棵果树的结果数。

【输出格式】

     输出仅一行,一个正整数,即满足条件的果篮最小容积。

【样例输入】

9 3

1 2 3 4 5 6 7 8 9

【样例输出】

17

【数据规模】

对于 30% 的数据,满足 n, k≦100、ai≦100 。

对于 60% 的数据,满足 n, k≦1000、ai≦105

对于 80% 的数据,满足 n, k≦10000、ai≦105

对于 100% 的数据,满足 n, k≦105 、ai≦109

解析

很显然这是一道二分题,记得加long long 就行了。

code

泉五培训Day4
#include<iostream>
#include<cstring>
#include<cstdio>
#define int long long
using namespace std;
const int n=1e5+5;
const int inf=0x3f3f3f3f;
int n,k;
int a[n],ans;
int minn=inf;
int maxn=-inf;
bool check(int v)
{
    if(maxn>v||minn>v) return 0;
    int cnt=1,water=v;
    for(int i=1;i<=n;i++)
    {
        if(a[i]<=water) water-=a[i];
        else if(a[i]>water)
        {
            cnt++;
            water=v-a[i];
        }
    }
    if(cnt<=k) return 1;
    return 0;
}
signed main()
{
    int l=1,r=0,mid;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        maxn=max(maxn,a[i]);minn=min(minn,a[i]);
        r+=a[i];
    }
    while(l<=r)
    {
        mid=(l+r)/2;
        if(check(mid))
        { 
            r=mid-1;
            ans=mid;
        }
        else l=mid+1;
    }
    cout<<ans;
    return 0;
}
view code

 

 

 

 

 

 

t2 食物

题目

【题目描述】

辉夜从月都弄了很多吃的回到了幻想乡,有n种不同的食物,第i种食物的美味度为ti,一份食物的大小为ui,共有vi份。但是麻烦的事情出现了,她要把这些食物运回永远亭,于是辉夜便弄来了m种运载工具。第i种运载工具可以运输大小总和不超过xi的食物,运输一次的费用是yi,总共可以运输zi次。

辉夜打算选取一些食物运回永远亭,他们的美味度之和(每份食物的和,即使他们都是同一种食物)至少是p。值得注意的是,一份食物可以被拆成几份分批次运输,达到永远亭后再组装起来。但是如果不把一份食物完整的运过去,是无法得到美味度的。辉夜想知道最少需要花费的运输费用是多少。由于辉夜的预算仅有50000,因此如果费用超过这个数或者无法获得p的美味度,输出“tat”。

【输入格式】

第一行一个数test,表示有test组数据。

对于每组数据,第一行有三个整数n,m,p。

接下来n行,每行三个整数t,u,v,描述一种食物。

最后m行,每行三个整数x,y,z,描述一种运载工具。

【输出格式】

 对于每组数据,输出辉夜想知道的答案。注意存在无解的情况。

【输入样例】

4

1 1 7

14 2 1

1 2 2

1 1 10

10 10 1

5 7 2

5 3 34

1 4 1

9 4 2

5 3 3

1 3 3

5 3 2

3 4 5

6 7 5

5 3 8

1 1 1

1 2 1

1 1 1

【样例输出】

4

14

12

tat

【数据规模】

test不会很大。

对于前20%的数据,n,m≤20。

对于前50%的数据,n,m≤30,ti,ui,vi,xi,yi,zi≤10。

对于100%的数据,1≤n,m≤200,0≤p≤50000,1≤ti,ui,vii,xi,yi,zi≤100。

解析

我们把问题拆成两部分:

1、选出美味度和不小于p的食物并且空间最小。

2、选出空间之和不小于第一步的结果并且费用尽可能的少。

第一部分只需用背包即可解决。

第二部分我们不妨将状态和答案互换,以费用为状态,以空间为答案,因为答案不超过50000,所以这样是可行的。

code

泉五培训Day4
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int n=210;
const int m=50200;
int n,m,p;
int q,sum,ans;
int t[n],u[n],v[n];
int f[m],w[n*7],v[n*7];
int read()    //快读 
{
    int num=0;char ch=getchar();
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
    return num;
}
int main()
{
    int t=read();
    while(t--)
    {
    //求出最小空间
        sum=0;
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        memset(f,0,sizeof(f));
        n=read();m=read();p=read();
        for(register int i=1;i<=n;i++)
        {
            t[i]=read();u[i]=read();v[i]=read();
            int j;
            for(j=1;j<=v[i];j<<=1)
            {
                v[++sum]=t[i]*j;
                w[sum]=u[i]*j;
                v[i]-=j;
            }
            if(v[i])
            {
                v[++sum]=t[i]*v[i];
                w[sum]=u[i]*v[i];
            }
        }
        for(register int i=1;i<=sum;i++)
            for(register int j=m-1;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]);
        q=-1;
        for(register int i=1;i<m;i++) if(f[i]>=p){q=i;break;}//求出满足美味度不小于p的最小价值
        if(q<0)//不成立的情况
        {
            cout<<"tat"<<endl;
            for(register int i=1;i<=m;i++) q=read(),q=read(),q=read();
            continue;
        }
        //求出尽可能小的费用
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        memset(f,0,sizeof(f));
        sum=0;
        for(register int i=1;i<=m;i++)
        {
            t[i]=read();u[i]=read();v[i]=read();
            int j;
            //二进制拆分
            for(register int j=1;j<=v[i];j<<=1)
            {
                v[++sum]=t[i]*j;
                w[sum]=u[i]*j;
                v[i]-=j;
            }
            if(v[i])
            {
                v[++sum]=t[i]*v[i];
                w[sum]=v[i]*u[i];
            }
        }
        for(register int i=1;i<=sum;i++)
            for(register int j=50000;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]);
        ans=-1;
        for(register int i=1;i<=50000;i++) if(f[i]>=q){ans=i;break;}//求出最小花费
        if(ans<0){cout<<"tat"<<endl;continue;} 
        cout<<ans<<endl;
    }
    return 0;
}
view code

 

 

 

 

 

 

t3 到天堂的路

题目

【题目描述】

到天堂的道路是一个笛卡尔坐标系上一个nxm的长方形通道(顶点在(0,0)和(n,m)),小w从最左边任意一点进入,从右边任意一点走到天堂。

最左最右的距离为n,上下边界距离为m。

其中长方形内有k个star,每个star都有一个整点坐标,star的大小可以忽略不计。

每个star以及长方形上下两个边缘(宇宙的边界)都有引力,所以为了成功到达heaven小w离他们越远越好。

请问小w走到终点的路径上,距离所有星星以及边界的最小距离最大值可以为多少?

【输入格式】

 一行三个整数n,m,k。

接下来k行,每行两个整数xi,yi,表示一个点的坐标。

【输出格式】

 一行一个整数表示答案,绝对误差不能超过10-6

【输入样例】

10 5 2

1 1

2 3

【输出样例】

1.11803399

【数据规模】

对于20%的数据,k≤10。

对于50%的数据,k≤400。

对于80%的数据,k≤1000。

对于100%的数据,k≤6000,n,m≤106

解析

最小距离的最大值,考虑从将几个点,从下界连到上界,这条路径中的最长边的一半,即我们想要的答案。

一条路径的最长边,即最大值。

所有路径中的最长边的最小值,即最小距离。

所以求出最长边的最小值即可。

我们要找到所有路径中的所有最长边(相对于该条路径而言),然后在这些最长边中找到一个最小值,最小值除以二即为答案。

code

泉五培训Day4
#include<iostream>
#include<cstdio>
#include<cmath>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int n=6000+5;
int water[n];
int n,m,k,x[n],y[n];
double dis[n],ans;
double calc(int x,int y,int l,int r)
{
    return sqrt((double)(x-l)*(x-l)+(double)(y-r)*(y-r));
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++) cin>>x[i]>>y[i];
    for(int i=1;i<=k;i++) dis[i]=m-y[i];
    dis[k+1]=m;
    dis[0]=2e9;
    while(1)
    {
        int mi=0;
        for(int i=1;i<=k+1;i++)
            if(!water[i] && dis[i]<dis[mi]) mi=i;
        ans=max(ans,dis[mi]);
        if(mi==k+1)
        {
            cout<<ans/2;
            return 0;
        }
        for(int i=1;i<=k;i++) dis[i]=min(dis[i],calc(x[i],y[i],x[mi],y[mi]));
        dis[k+1]=min(dis[k+1],y[mi]);
        water[mi]=1;
    }
    return 0;
}
view code