20160807 软件开发 二分暴力

本文介绍了一个软件开发项目的人员调度算法,旨在通过合理分配任务来最小化项目完成时间。采用二分查找结合深度优先搜索的方法,考虑了不同人员完成任务所需时间的差异。

、软件开发(software.cpp)
一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。写一个程序,求出公司最早能在什么时候交付软件。
【输入】
输入文件第一行包含两个由空格隔开的整数n和m,其中1≤n≤100,1≤m≤100。接下来的n行每两个用空格隔开的整数d1和d2,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中
l≤d1,d2≤100。
【输出】
输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。
【样例】
Software.in
3 20
1 1
2 4
1 6
software.out
18

二分答案,暴力验证是否可行。至于上界如何选择,我们可以让做软件1最快的人自己做完软件1,让做软件2最快的另一个人自己做完软件2,以此作为上界。对于每个答案,暴力枚举每个人做多少个1模块,由于期限一定,就可以知道做多少2模块。进行剪枝:已经把剩余的1模块全部做完,就无须再做(需要保证这一层至少已经向下搜索过一次,否则前面的人把1做完了这一层就直接跳出去了);做这个数量的1会导致后面的人做不完1,就需要多做;如果多做点1仍然可以把剩下的2全做完,就尽量多做;如果后面的人已经做不完2,就不能让这个人再做1了。有了这些剪枝,就可以暴虐DP了。(题解是二分DP,用f[i][j]表示前i个人做j个1模块时能做的最大2模块数,最后判断f[n][m]是否大于m)。
自己的代码:

#include<cstdio>
#include<algorithm>
#define gm 102
using namespace std;
int n,m,t=gm;
struct mky
{
    int d1,d2;
    bool operator < (const mky &b) const
    {return d2<b.d2||(d2==b.d2&&d1<b.d1);}
}p[gm];
int r1,r2,lm;
int sum[2][gm];
bool solved=0;
void dfs(int x)
{
    if(x==n)
    {
        if(r1<=0&&r2<=0) solved=1;
        return;
    }
    int y,z;
    bool w=0;
    for(int i=0,j=lm/p[x].d1;i<=j;i++)
    {
        if(r1<i&&w) break;
        if(r1-i>sum[0][x+1]) continue;
        y=(lm-i*p[x].d1)/p[x].d2;
        if(r2<y)
        {
            z=(lm-i*p[x].d1-p[x].d1)/p[x].d2;
            if(r2<=z&&i!=j) continue;
        }
        if(r2-y>sum[1][x+1]) break;
        r1-=i;
        r2-=y;
        dfs(x+1);
        if(solved) return;
        w=1;
        r1+=i;
        r2+=y;
    }
}
inline bool check(int k)
{
    solved=0;
    r1=r2=m;
    lm=k;
    for(int i=n-1;i>=0;i--)
    sum[0][i]=lm/p[i].d1+sum[0][i+1],sum[1][i]=lm/p[i].d2+sum[1][i+1];
    dfs(0);
    return r1<=0&&r2<=0;
}
int main()
{
    freopen("software.in","r",stdin);
    freopen("software.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&p[i].d1,&p[i].d2);
        if(p[i].d1<t) t=p[i].d1;
    }
    if(n==1)
    {
        printf("%d",m*(p[0].d1+p[0].d2));
        return 0;
    }
    sort(p,p+n);
    if(p[0].d1==t) t=p[1].d1;
    int l=1,r=m*p[0].d2,mid;
    if(r<m*t) r=m*t;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d",l);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值