计划安排 【包懂有图】(网络流) gzoi

广州的同学看这里:

http://www.gdgzoi.com/JudgeOnline/problem.php?cid=1045&pid=2

Description

Dramatic的工厂最近生意红火!有N位客户希望工厂为他们加工产品。每位客户都提供了需要加工的产品的类型,产品到达工厂的时间r和最迟完成加工的时间d。Dramatic根据需要加工的产品类型预计了每个产品加工所需的时间t。工厂里的生产车间一共有M台机器。每个产品在每台机器上都可以加工,但是,一台机器在任何时候最多只能加工一件产品,而一件产品在任何时候也最多只能被一台机器加工。同时,我们可以在某台机器正在加工时将工作打断,换另一个产品加工。Dramatic希望你帮他计算一下,能否找到一个方案,使得所有的产品都在规定的时间内完成加工?

输入第一行包含一个整数Q,表示数据组数。接下来Q组数据,每组数据的第一行包含两个整数N,M,表示需要加工的产品的数量、机器的数量。接下来N行,每行三个整数ti、ri、di,表示加工产品所需的时间,产品到达工厂的时间以及最迟完成加工的时间(即产品可以在[ri,d)内被加工]。

输出包含Q行,每行对应一组数据的答案。如果第i组数据能搞找到一个方案,则第i行包含一个Yes,否则包含一个No。

样例

Arrange.in

arrange.out

2

2 1

3 5 9

4 8 12

3 1

2 2 9

2 3 5

3 5 8

Yes

Yes

【数据范围】

1≤N≤300,1≤M≤300

这道题目的思路还是比较简单明了的

首先我们想到的是把一个时间一个数据拆开了。

但是,在一番深思熟虑过后我们可以发现,完全可以把一块一块的时间做一个集合:

我不想打字了,画了张图自己看吧:(例一数据一)

看了图片是不是有一个大概印象:

此时我们只需阀门放出的flow全部流回汇点就行(yes)。

时间集与汇点连线容量为:时间集长度*机器数量(自己想想why);

接下来是贴代码:

#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
using namespace std;
const int INF=0x3f3f3f3f;
const int N=400005;
const int E=800005;
struct edge{int x,y,w,next;}e[E];
struct seg{int l,r,len;}s[N];
std:: queue<int> que;
int cur[N],ls[N],edCnt;
int dis[N],l[N],r[N],c[N];
bool rec[N];
int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}
void addEdge(int x,int y,int w) {
    e[++edCnt]=(edge){x,y,w,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge){y,x,0,ls[y]}; ls[y]=edCnt;
    // printf("%d %d %d\n", x,y,w);
}
int bfs(int st,int ed) {
    while (!que.empty()) que.pop();
    que.push(st);
    fill(dis,-1); dis[st]=1;
    while (!que.empty()) {
        int now=que.front(); que.pop();
        for (int i=ls[now];i;i=e[i].next) {
            if (dis[e[i].y]==-1&&e[i].w>0) {
                dis[e[i].y]=dis[now]+1;
                if (e[i].y==ed) return 1;
                que.push(e[i].y);
            }
        }
    }
    return 0;
}
int find(int now,int ed,int mn) {
    if (now==ed||!mn) return mn;
    int ret=0;
    for (int &i=cur[now];i;i=e[i].next) {
        if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {
            int d=find(e[i].y,ed,std:: min(mn-ret,e[i].w));
            e[i].w-=d; e[i^1].w+=d; ret+=d;
            if (ret==mn) break;
        }
    }
    return ret;
}
int dinic(int st,int ed) {
    int ret=0;
    while (bfs(st,ed)) {
        rep(i,st,ed) cur[i]=ls[i];
        ret+=find(st,ed,INF);
    }
    return ret;
}

//模板,到处都是。
int main(void) {
    int T=read();
    while (T--) {
        int n=read(),m=read();
        int cnt=0,mxr=0,tot=0; edCnt=1;
        fill(rec,0); fill(ls,0);
        rep(i,1,n) {
            c[i]=read();
            l[i]=read(),r[i]=read();
            rec[l[i]]=rec[r[i]]=1;
            mxr=std:: max(mxr,r[i]);//读取最大时间,为下面分段提供界限;
            tot+=c[i];
        }
        s[++cnt].l=1;
        rep(i,2,mxr)
            if (rec[i]) {
                s[cnt].r=i;
                s[cnt].len=s[cnt].r-s[cnt].l;//把时间轴的时间分段并标号(自己画一个轴);
                s[++cnt].l=i;
            }
        cnt--;
        rep(i,1,n) {
            addEdge(0,i,c[i]);//建立源点与任务的联系,及阀门;
            rep(j,1,cnt) {
                if (l[i]<=s[j].l&&r[i]>=s[j].r) {
                    addEdge(i,j+n,s[j].len);//建立符合该任务时间联系;
                }
            }
        }
        rep(j,1,cnt) {
            addEdge(j+n,n+cnt+1,s[j].len*m);//建立时间与汇点联系;
        }
        int mxFlow=dinic(0,n+cnt+1);//打开阀门,看汇的的流量;
        if (mxFlow==tot) puts("Yes");//全部时间可流回便满足;
        else puts("No");
    }
    return 0;
}

 

 

 

猜你喜欢

转载自blog.csdn.net/Wyt_code/article/details/81545337