最大流——HDU3572 Task Schedule

HDU3572 Task Schedule

题解:
题意为由M台机器,处理N个事件,每个事件有开始时间结束时间和处理时长。每台机器在一个时间只能处理一个事件,每个事件可以分为很多段,由不同的机器进行处理。求N个事件能不能顺利处理完。

构图:
将N个事件为这位1-N个点,因为E<=500,可以将时间分为500个点,源点1,事件点2-N+1,时间点为N+2 - N+500+1,汇点为n = N+500+2。将原点与所有事件点建边,权值为Pi,将所有事件点与所有能处理该事件的时间点建边,权值为1,因为一个时间只能处理一个事件一个时间单位部分,将所有时间点与汇点建边,权值为M,因为每个时间点都有M台机器可用。
然后用SAP或者Dinic跑最大流

AC code

//Max_flow
//@2018/05/04 Friday
//SAP  O(n^2 * m)  O(m*3*2)
//by Tawn 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1000 + 100;
const int maxm = 1000000 + 10;

int n,m;
int head[maxn];//链式前向星
int tot = 0;
int Pi[maxn];
int Si[maxn];
int Ti[maxn];


struct edge
{
  int to;
  int c;
  int next;
  edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
 }es[maxm*2];//记录边 注意是2倍

void add_edge(int u, int v, int c)
{
    es[tot] = edge(v,c,head[u]);
    head[u] = tot++;
}


int SAP(int s, int t)
{
    int numh[maxn],h[maxn],ce[maxn],pre[maxn];
    //numh 记录gap优化的统计高度数量数组,h 距离标号数组,ce 当前弧,pre前驱数组
    int f, ans = 0, u, temp, neck, i; //初始化最大流为0
    memset(h,0,sizeof(h));
    memset(numh,0,sizeof(numh));
    memset(pre,-1,sizeof(pre));
    for(i = 1; i <= n; i++)  ce[i] = head[i];
    numh[0] = n;
    u = s;
    while(h[s] < n)
    {
        //寻找增广路
        if(u == t)
        {
            f = INF;
            for(i = s; i != t; i = es[ce[i]].to)
            {
                if(f > es[ce[i]].c)
                {
                    neck = i;
                    f = es[ce[i]].c;
                }
            }
            for(i = s; i != t; i = es[ce[i]].to)
            {
                temp = ce[i];
                es[temp].c -= f;
                es[temp^1].c += f;
            }
            ans += f;
            u = neck;
        }

        //寻找可行弧
        for(i = ce[u]; i != -1; i = es[i].next)
            if(es[i].c && h[u] == h[es[i].to] + 1)  break;

       //寻找增广路
        if(i != -1)
        {
            ce[u] = i;
            pre[es[i].to] = u;
            u = es[i].to;
        }
        else
        {
            if(!--numh[h[u]]) break; //gap optimization
            ce[u] = head[u];
            for(temp = n, i = head[u]; i != -1; i = es[i].next)
                if(es[i].c)  temp = min(temp, h[es[i].to]);

            h[u] = temp + 1;
            ++numh[h[u]];
            if(u != s) u = pre[u];//重标号并且从当前点前驱重新增广 
        }

    }
    return ans;
}



int main()
{
   int T;
   scanf("%d",&T);
   int t = T;
   while(T--)
   {
   int N,M;
   scanf("%d%d",&N,&M);
   tot = 0;
   memset(head,-1,sizeof(head));
   int sp = 0;
   for(int i = 1; i <= N; i++)  {scanf("%d%d%d",&Pi[i],&Si[i],&Ti[i]); sp += Pi[i];}

   n = 2 + N + 500;

   for(int i = 2; i < N+2; i++)  
   {
    add_edge(1,i,Pi[i-1]);
    add_edge(i,1,0);
   }

   for(int i = N+2; i < n; i++)
   {
    add_edge(i,n,M);
    add_edge(n,i,0);
   }

   for(int i = 2; i < N+2; i++)
   {
    for(int j = Si[i-1]; j <= Ti[i-1]; j++)
        {
            add_edge(i,j+N+1,1);
            add_edge(j+N+1,i,0);
        }
   }   
   int ans = SAP(1,n); 
   //cout << ans << endl;
   if(ans == sp) printf("Case %d: Yes\n",t - T);
   else printf("Case %d: No\n",t - T);
   cout << endl;
   }
   return 0;   
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值