【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");
	}
}


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