广州的同学看这里:
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;
}