HDU3572 Task Schedule(最大流)

有n个任务,m个机器,对于第i个任务,必须在第si天之后开始,需要pi天完成且必须在第ei天之前完成。在一天中,一台机器只能干一个任务,一个任务只能被一台机器干。一个任务可以被中途打断,在不同的天用另外的机器完成。问你是否可以完成任务。 (n500,m200,1pi,si,ei500)
网络流的建模0 0
既然一个任务要pi天完成,那么虚拟一个源点s,向任务i连一条容量为pi的边,表示消耗的时间。第i个任务向si到ei的所有天数各连一条容量为一的边,因为每天的进度最多为1。最后,每天都向虚拟的汇点连一条容量为m的边,因为每天最多有m台机器工作。求出最大流,如果等于 pi ,那么可以完成任务。

#include<cstdio>
#include<vector>
#include<cstring>
#define MAXN 2010
using namespace std;
inline int Min(int a,int b)
{return a<b?a:b;}
struct E
{
    int v,w,op;
    E(){}
    E(int a,int b,int c){v = a; w = b; op = c;}
};
vector<E> g[MAXN];
int d[MAXN],vd[MAXN],n,m,s,t,maxnum,pi,si,ei,N,flow,sum;
int aug(int i,int augco)
{
    int j,augc = augco,mind = t-1,delta,sz = g[i].size();
    if(i == t) return augco;
    for(j = 0; j < sz; j++)
    {   
        int v = g[i][j].v;
        if(g[i][j].w)
        {
            if(d[i] == d[v]+1)
            {
                delta = Min(g[i][j].w,augc);
                delta = aug(v,delta);
                g[i][j].w -= delta;
                g[v][g[i][j].op].w += delta;
                augc -= delta;
                if(d[1] >= t) return augco - augc;
                if(augc == 0) break;
            }
            if(d[v] < mind) mind = d[v];
        }
    }
    if(augc == augco)
    {
        vd[d[i]]--;
        if(vd[d[i]] == 0) d[1] = t;
        d[i] = mind+1;
        vd[d[i]]++;
    }
    return augco - augc;
}
void sap()
{
    memset(d,0,sizeof d);
    memset(vd,0,sizeof vd);
    vd[0] = t;
    flow = 0;
    while(d[1] < t)
        flow += aug(1,0x3f3f3f3f);
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int o = 1; o <= T; o++)
    {
        sum = 0;
        scanf("%d%d",&n,&m);
        for(int i = 2; i <= n+1; i++)
        {
            scanf("%d%d%d",&pi,&si,&ei);
            if(ei > maxnum) maxnum = ei;
            sum += pi;
            for(int j = si+n+1; j <= ei+n+1; j++)
            {
                g[i].push_back(E(j,1,g[j].size()));
                g[j].push_back(E(i,0,g[i].size()-1));
            }
            g[1].push_back(E(i,pi,g[i].size()));
            g[i].push_back(E(1,0,g[1].size()-1));
        }
        N = 1+n;
        t = 1+n+maxnum+1;
        for(int i = N+1; i <= N+maxnum; i++)
        {
            g[i].push_back(E(t,m,g[t].size()));
            g[t].push_back(E(i,0,g[i].size()-1));
        }
        sap();
        if(flow == sum) printf("Case %d: Yes\n\n",o);
        else printf("Case %d: No\n\n",o);
        for(int i = 1; i <= t; i++)
            g[i].clear();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值