1.题意:工厂里有n个任务,每个任务都有最早开始时间si,完成所需时间pi,最晚结束时间ei;现在工厂里有m台机器,每台机器每次只能执行一个任务,每个任务可以在执行过程中中断然后放到另一台机器上执行。问这些任务能否在期限内完成。
2.分析:完成所有的任务所需时间为 Sum(pi),如果我们最大能力的去让机器处理可处理的任务,那么机器处理的总时间也就是处理所有任务最大化的时间,如果这个时间>=Sum(pi),那么我们的任务也就都能完成,否则无法都完成。
那么怎么求出这个最大化的时间呢?这里需要构建一个网络流最大流模型。
每个任务看作一个源点,该任务与每一个能执行该任务的天建一条边,容量为1,因为每一天每一台机器只能执行一个任务。然后建立一个超级汇点,连接每一个天,容量为m,因为每一天最多处理m个任务,贡献m的时间。最后多个源点当然要建立一个超级源点!连接每一个任务,容量为该任务所需的时间。对于这个图跑最大流,判断即可。
注:一定要用Dinic 的当前弧优化,否则超时QAQ~
3.代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define INF 1e18
typedef long long LL;
const int maxnM = 502000 + 7;
const int maxnN = 1100;
struct Edge{
int to,next;
LL cap,flow;
}edge[maxnM];
int n,m,tot,head[maxnN],dist[maxnN],cur[maxnN];
int vis[507];
void addEdge(int a,int b,LL c){
edge[tot].to = b;edge[tot].cap = c;edge[tot].flow = 0;edge[tot].next = head[a];head[a] = tot++;
edge[tot].to = a;edge[tot].cap = 0;edge[tot].flow = 0;edge[tot].next = head[b];head[b] = tot++;
}
bool BFS(int s,int t){
memset(dist,0,sizeof(dist));
dist[s] = 1;
queue<int> que;
que.push(s);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u];~i;i = edge[i].next){
int v = edge[i].to;
if(!dist[v]&&edge[i].cap > edge[i].flow){
dist[v] = dist[u] + 1;
que.push(v);
}
}
}
if(dist[t] > 0)return true;
return false;
}
LL DFS(int p,int t,LL nowFlow){
if(p==t||nowFlow==0)return nowFlow;
LL minFlow = 0;
for(int &i = cur[p];~i;i = edge[i].next){
int v = edge[i].to;
if(dist[v] == dist[p] + 1&&edge[i].cap >edge[i].flow){
LL f = DFS(v,t,min(nowFlow,edge[i].cap - edge[i].flow));
if(f==0)continue;
edge[i].flow+=f;
edge[i^1].flow-=f;
minFlow+=f;
nowFlow-=f;
if(nowFlow==0)break;
}
}
return minFlow;
}
LL Dinic(int s,int t){
LL flow = 0;
while(BFS(s,t)){
for(int i = s;i<=t;i++)cur[i] = head[i];//当前弧优化!!!
LL res = DFS(s,t,INF);
flow+=res;
}
return flow;
}
int main()
{
int T;
scanf("%d",&T);
int t = 0;
while(T--){
t++;
tot = 0;
LL sum = 0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
int cnt = n+1;
for(int i = 1;i<=n;i++){
int p,s,e;
scanf("%d%d%d",&p,&s,&e);
sum+=p;
addEdge(0,i,(LL)p);//超级源点与每一个任务建边
for(int j = s;j<=e;j++){
if(!vis[j]){
vis[j] = cnt++;//给出现的天一个编号
}
addEdge(i,vis[j],1);//任务i与每一天建边
}
}
for(int i = n+1;i<=cnt-1;i++){
addEdge(i,cnt,(LL)m);//每一天与超级汇点建边
}
LL ans = Dinic(0,cnt);
if(ans==sum)printf("Case %d: Yes\n\n",t);
else printf("Case %d: No\n\n",t);
}
return 0;
}