【JZOJ 省選模擬】安排

題目

Description
【題目背景】
ysgh 和 ysgh 在進行體育鍛煉。
今天他們看到了操場上的樹,想到操場上的體育課的場地安排。
【題目描述】
操場分爲跑道和跑道中的足球場兩部分。
現在有 n 個班上短跑課,m 個班上足球課。跑道總共可以分爲 x部分,每部分恰好能容納 1 個班上課,足球場總共可以分爲 y 部分,每部分恰好能容納 1 個班上課。短跑課只能在跑道上上,足球課在足球場和跑道都可以上。

每一個班上體育課的時間爲ሾ᮸ࣙ䮈ɽ࣋ࣙ,這表示這個班級會在 xi-yi這段時間內上體育課(包括 xi,不包括 yi)。上體育課時每個班級的場地必須固定,不能隨意調動。
ysgh 覺得這個問題可以亂搞,但是他不屑於寫,於是他把這個問題交給了你。

Input
本題有多組測試數據。
第一行一個數字表示測試數據組數 T。
對於每組數據,第一行四個數字 n,m,x,y。
接下來 n 行,第 i 行兩個數字 xi,yi,表示第 i 個短跑課的班級上課的起始終止時間。
接下來 m 行,第 i 行兩個數字 xi,yi,表示第 i 個上足球課的班級上課的起始終止時間。

Output
對於每組數據:
若不存在解,輸出 NO,否則第一行輸出 YES。
第二行 n 個數字,第 i 個數字表示第 i 個上短跑課的班級佔用的體育場地編號。若編號 id<=x 則佔用了第 id 號短跑場,否則佔用了第 id-x 號足球場。
第三行 m 個數字,第 i 個數字表示第 i 個上足球課的班級佔用的體育場地編號。編號表示方式同上。

Sample Input
1
1 3 1 1
1 7
7 10
1 5
6 10

Sample Output
YES
1
1 2 2

Data Constraint
在這裏插入圖片描述

思路

考慮若有短跑課,我們考慮足球場地的分配問題,分配完之後直接
根據之前的貪心原則分配短跑場地。
考慮每個t + 0.5的時刻在合法的情況下最多有幾個空閒的足球場
地。
設短跑課X節,足球課Y 節,則在t + 0.5的時刻最多隻能有
min(y, x + y − X − Y )塊空閒的足球場地。
此時若時刻0到時刻inf的流量不少於y則無解,否則一定存在解。
解的構造可以直接根據退流得到。
最後記得將時間離散化掉優化建點。

代碼

#include <bits/stdc++.h>
using namespace std;

const int maxn = 605,Inf = 1 << 30;

int gi()
{
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	int sum = 0;
	while ('0' <= c && c <= '9') sum = sum * 10 + c - 48,c = getchar();
	return sum;
}

int n,m,A,B,x[maxn],y[maxn],*q[maxn << 1],ti;
int vis[maxn],now[maxn],ans[maxn],sum[maxn << 1],Id[maxn];
vector<int> vec[maxn << 1];

struct edge
{
	int to,next,cap;
} e[maxn * 5];
int h[maxn << 1],cur[maxn << 1],dis[maxn << 1],tot;

void add(int u,int v,int w)
{
	//printf("%d %d %d\n",u,v,w);
	e[++tot] = (edge) {v,h[u],w}; h[u] = tot;
	e[++tot] = (edge) {u,h[v],0}; h[v] = tot;
}

bool bfs(int s,int t,int E)
{
	int u,l,r,q[maxn << 1];
	memset(dis + 1,0,sizeof(int) * ti);
	l = 0; q[r = 1] = s; dis[s] = 1;
	while (l < r) {
		u = q[++l];
		for (int i = h[u],v; v = e[i].to,i; i = e[i].next)
			if ((i & 1) != E && !dis[v] && e[i].cap) dis[v] = dis[u] + 1,q[++r] = v;
	}
	return dis[t];
}

int dfs(int u,int t,int a,int E)
{
	if (u == t || !a) return a;
	int flow = 0,f;
	for (int &i = cur[u],v; v = e[i].to,i; i = e[i].next)
		if ((i & 1) != E && dis[v] == dis[u] + 1 && (f = dfs(v,t,min(a,e[i].cap),E))) {
			a -= f; flow += f;
			e[i].cap -= f; e[i ^ 1].cap += f;
			if (!a) break;
		}
	return flow;
}

int max_flow(int s,int t,int f,int E)
{
	int res = 0;
	while (bfs(s,t,E) && res < f) {
		memcpy(cur + 1,h + 1,sizeof(int) * ti);
		res += dfs(s,t,f,E);
	}
	return res;
}

int main()
{
	freopen("arrange.in","r",stdin); freopen("arrange.out","w",stdout);
	int T = gi();
	while (T--) 
	{
		n = gi(); m = gi(); A = gi(); B = gi();

		int Min = -1e9,Max = 1e9 + 1;
		q[tot = 1] = &Min; q[++tot] = &Max;
		for (int i = 1; i <= n; ++i) x[i] = gi(),y[i] = gi(),q[++tot] = x + i,q[++tot] = y + i;
		for (int i = 1; i <= m; ++i) x[n + i] = gi(),y[n + i] = gi(),q[++tot] = x + n + i,q[++tot] = y + n + i;
		sort(q + 1,q + tot + 1,[](int *a,int *b) {return *a < *b;});
		ti = 0;
		for (int lst = -1,i = 1; i <= tot; ++i) {
			if (*q[i] == lst) *q[i] = ti;
			else lst = *q[i],*q[i] = ++ti;
		}
		
		memset(sum + 1,0,sizeof(int) * ti);
		for (int i = 1; i <= n + m; ++i)
			for (int j = x[i]; j < y[i]; ++j) ++sum[j];
		
		tot = 1; memset(h + 1,-1,sizeof(int) * ti);
		bool flg = 1;
		for (int i = 1; i < ti; ++i) {
			if (A + B < sum[i]) {flg = 0; break;}
			add(i,i + 1,min(B,A + B - sum[i]));
		}
		if (!flg) {puts("NO"); continue;}
		for (int i = n + 1; i <= n + m; ++i) add(x[i],y[i],1),Id[i - n] = tot;

		if (max_flow(1,ti,Inf,-1) != B) puts("NO");
		else {
			puts("YES");
			memset(vis + 1,0,sizeof(int) * m);
			memset(ans + 1,0,sizeof(int) * (n + m));
			for (int i = 1; i <= m; ++i) vis[i] = !e[Id[i]].cap;
			for (int i = 1; i <= B; ++i) {
				max_flow(ti,1,1,0);
				for (int j = 1; j <= m; ++j)
					if (!vis[j] && !e[Id[j]].cap) vis[j] = 1,ans[n + j] = A + i;
			}
			for (int i = 1; i <= ti; ++i) vec[i].clear();
			for (int i = 1; i <= n + m; ++i) if (!ans[i]) vec[x[i]].push_back(i);
			memset(now + 1,0,sizeof(int) * A);
			for (int i = 1; i <= ti; ++i)
				for (int t : vec[i])
					for (int j = 1; j <= A; ++j)
						if (y[now[j]] <= x[t]) {now[j] = t; ans[t] = j; break;}
			for (int i = 1; i <= n; ++i) printf("%d ",ans[i]),assert(ans[i]);
			puts("");
			for (int i = 1; i <= m; ++i) printf("%d ",ans[n + i]),assert(ans[n + i]);
			puts("");
		}
	}
	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章