传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2883
题意:
给定n个顾客,第i号顾客在si到达,点了ni个羊肉串,每个羊肉串需要ti个时间烤好。顾客想要在ei得到,一个烤炉只烤m串。问你是否能满足所有顾客的要求?能的话输出“Yes”,否则输出“No”。
注意:这ni个羊肉串可以被分开来考,一个单独的羊肉串也能分开烤(比如一个单独的羊肉串需要ti时间,我们把它分成ti份同时烤的话,那么一个羊肉串可以在1个单位时间内拷完)
注意:每个顾客的任务必须在(si,ei]半开半闭的区间内完成.
基本的任务分配题,还是附上大神的讲解:http://blog.youkuaiyun.com/u013480600/article/details/38984057
分析:
本题与HDU3572有点类似:
http://blog.youkuaiyun.com/rain722/article/details/54601227其实本题的本质就是HDU3572的思想,每个顾客其实提出的是需要ni*ti个单位时间任务(甚至可以在1个时刻同时完成,因为一串羊肉串都可以在1个时刻烤完),但是你每个时间只能提供m个单位时间做任务. 但是这个题目的时间点覆盖1到100W,明显不能再把每个单独的时间看成一个点了,所以这题要把每个不重叠的子时间区间看成一个点.
首先读入所有任务的开始时间s[i]和结束时间e[i],然后对这些时间点排序,去重,得到cnt个时间点,然后我们就能得到cnt-1个半开半闭的子时间区间(前后两个子区间边界不重叠,且所有区间连起来正好覆盖了原来的整个大时间区间,该大时间区间也是半开,半闭的).
建图: 源点s编号0, n个任务编号1到n, cnt-1个区间编号n+1到n+cnt, 汇点t编号n+cnt+1.
源点到每个任务i有边(s,i,ni*ti)
每个时间区间j到汇点有边(j,t, 该区间覆盖的单位时间点数)
如果任务i包含时间区间j,那么有边(i,j,INF)
求最大流,看最大流 是否== 所有任务需要的单位时间之和即可.
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define PI acos(-1.0)
#define eps 1e-8
#define ll long long
#define MEM(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define MII map<int,int>::iterator
#define MLL map<LL,LL>::iterator
#define pii pair<int,int>
#define SI set<int>::iterator
#define SL set<LL>::iterator
#define dug printf("bug-------bug-------bug\n")
using namespace std;
const int maxn = 600+5;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(){}
Edge(int f, int t, int c, int fl):from(f), to(t), cap(c), flow(fl){}
};
struct Dinic
{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
int d[maxn];
int cur[maxn];
bool vis[maxn];
void init(int n, int s, int t)
{
this->n = n;this->s = s;this->t = t;
edges.clear();
for(int i = 0; i < n; i++)
G[i].clear();
}
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS()
{
queue<int> q;
memset(vis, false, sizeof(vis));
vis[s] = true;
d[s] = 0;
q.push(s);
while(!q.empty())
{
int x = q.front();
q.pop();
for(int i = 0; i < G[x].size(); i++)
{
Edge e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = true;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a)
{
if(x == t || a == 0)
return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(d[e.to] == d[x]+1 && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0)
break;
}
}
return flow;
}
int max_flow()
{
int ans = 0;
while(BFS())
{
memset(cur,0,sizeof(cur));
ans += DFS(s, INF);
}
return ans;
}
}DC;
int N, M;
int s[maxn], n[maxn], e[maxn], t[maxn];
int time[maxn];
int full_flow;
int main()
{
while(scanf("%d%d", &N, &M) == 2)
{
full_flow = 0;
int cnt = 0;
for(int i = 1; i <= N; i++)
{
scanf("%d%d%d%d", &s[i], &n[i], &e[i], &t[i]);
time[cnt++] = s[i];
time[cnt++]= e[i];
full_flow += n[i]*t[i];
}
sort(time, time+cnt);
cnt = unique(time, time+cnt) - time;
int src = 0, dst = N + cnt + 1;
DC.init(N+cnt+2, src, dst);
for(int i = 1; i <= N; i++)
DC.AddEdge(src, i, n[i]*t[i]);
for(int i = 1; i <= cnt-1; i++)
{
DC.AddEdge(N+i, dst, (time[i]-time[i-1])*M);
for(int j = 1; j <= N; j++)
if(s[j] <= time[i-1] && time[i] <= e[j])
DC.AddEdge(j, N+i, INF);
}
printf("%s\n", DC.max_flow() == full_flow ? "Yes":"No");
}
return 0;
}