【HDU】 2883 kebab(最大流+时间段离散化)

思路:这道题目应该说看懂题意很重要。看懂之后就很简单了。

 有一个烧烤机,每个单位时间最多能烤 m 块肉,现在有 n 个人来买烤肉,每个人到达时间为 si,离开时间为 ei,点的烤肉数量为 ci,点的烤肉所需烘烤时间为 di,其实这边的ci和di有点描述的不清楚。明白一点的描述应该说的是,点的烤肉体积为ci,需要等待的时间为di。

          每个人要烤的肉可以分成若干份在同时烤,问是否存在一种方案可以满足所有顾客的需求。

这边所用到的技巧是,将时间段离散化,方法是将结束时间和开始时间一起从小到大排序,就可以得到所有的时间段。这个时间段向超级汇点走的最大流量为时间间隔dis*n(每单位时间可以烤的肉的数量)

每一个顾客可以向合适的一个时间段内走流量,最后判断总流量是否等于需求的数量就可以了。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100010
#define MAXM 400040
#define INF 0x7ffffff
int head[MAXN], dep[MAXN], gap[MAXN], cur[MAXN];
int times[MAXN << 1];
int si[MAXN], ei[MAXN], ni[MAXN], ti[MAXN];
int cnt;
int bit[11];
int num[1025];
//将情况相同的点,也就是可以到一样的行星上的人给合并成一个人,只是流量增多了.
struct edge
{
	int v;
	int cap;
	int flow;
	int next;
}edg[MAXM];

struct work
{
	int p, s, e;
}w[MAXN];
void init()
{
	cnt = 0;
	memset(head, -1, sizeof(head));
	memset(num, 0, sizeof(num));
}

void addedge(int u, int v, int w, int rw = 0)
{
	edg[cnt].v = v;
	edg[cnt].cap = w;
	edg[cnt].flow = 0;
	edg[cnt].next = head[u];
	head[u] = cnt++;
	edg[cnt].v = u;
	edg[cnt].cap = rw;
	edg[cnt].flow = 0;
	edg[cnt].next = head[v];
	head[v] = cnt++;
}
int Q[MAXN];
void BFS(int start, int end)
{
	memset(dep, -1, sizeof(dep));
	memset(gap, 0, sizeof(gap));
	gap[0] = 1;
	int front = 0, rear = 0;
	dep[end] = 0;
	Q[rear++] = end;
	while (front != rear)
	{
		int u = Q[front++];
		for (int i = head[u]; i != -1; i = edg[i].next)
		{
			int v = edg[i].v;
			if (dep[v] != -1)continue;
			Q[rear++] = v;
			dep[v] = dep[u] + 1;
			gap[dep[v]]++;
		}
	}

}

int S[MAXN];
int sap(int start, int end, int n)
{
	BFS(start, end);
	memcpy(cur, head, sizeof(head));
	int top = 0;
	int u = start;
	int ans = 0;
	while (dep[start] < n)
	{
		if (u == end)
		{
			int Min = INF;
			int inser;
			for (int i = 0; i < top; i++)
			if (Min>edg[S[i]].cap - edg[S[i]].flow)
			{
				Min = edg[S[i]].cap - edg[S[i]].flow;
				inser = i;
			}
			for (int i = 0; i < top; i++)
			{
				edg[S[i]].flow += Min;
				edg[S[i] ^ 1].flow -= Min;
			}
			ans += Min;
			top = inser;
			u = edg[S[top] ^ 1].v;
			continue;
		}
		bool flag = false;
		int v;
		for (int i = cur[u]; i != -1; i = edg[i].next)
		{
			v = edg[i].v;
			if (edg[i].cap - edg[i].flow&&dep[v] + 1 == dep[u])
			{
				flag = true;
				cur[u] = i;
				break;
			}
		}
		if (flag)
		{
			S[top++] = cur[u];
			u = v;
			continue;
		}
		int Min = n;
		for (int i = head[u]; i != -1; i = edg[i].next)
		if (edg[i].cap - edg[i].flow&&dep[edg[i].v] < Min)
		{
			Min = dep[edg[i].v];
			cur[u] = i;
		}
		gap[dep[u]]--;
		if (!gap[dep[u]])return ans;
		dep[u] = Min + 1;
		gap[dep[u]]++;
		if (u != start)u = edg[S[--top] ^ 1].v;
	}
	return ans;
}

int Scan()//读入外挂  
{
	int res = 0, ch, flag = 0;

	if ((ch = getchar()) == '-')                //判断正负  
		flag = 1;

	else if (ch >= '0' && ch <= '9')            //得到完整的数  
		res = ch - '0';
	while ((ch = getchar()) >= '0' && ch <= '9')
		res = res * 10 + ch - '0';

	return flag ? -res : res;
}

int main()
{
	int n, k;
	while (~scanf("%d%d", &n, &k))
	{
		int cnt = 0;
		init();
		int res = 0;
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d%d%d", &si[i], &ni[i], &ei[i], &ti[i]);
			times[cnt++] = si[i];
			times[cnt++] = ei[i];
			res += ni[i] * ti[i];
			addedge(0, i, ni[i] * ti[i]);
		}
		sort(times, times + cnt);
		int E = n + cnt + 2;
		for (int i = 0; i < cnt-1; i++)
			addedge(n + i + 1, E, (times[i + 1] - times[i]) * k);
		for (int i = 1; i <= n; i++)
		for (int j = 0; j < cnt;j++)
		if (si[i] <= times[j] && times[j + 1] <= ei[i])
			addedge(i, n + j + 1, INF);
		if (res == sap(0, E, E))
			puts("Yes");
		else
		puts("No");
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章