【SDOI2011】工作安排

题面

题解

如果没有分段函数的限制的话就很好做了

但是我们发现分段函数的段很少,我们就可以将每一段拆开,

强制限制一定流量就可以了

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<algorithm>
#include<queue>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x))

inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while(ch != '-' && (!isdigit(ch))) ch = getchar();
	if(ch == '-') w = -1, ch = getchar();
	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int maxn(1010), maxm(500010);
struct edge { int next, to, cap, dis; } e[maxm];
int head[maxn], e_num = -1, n, S, T, m;
int pre[maxn], pre_e[maxn], vis[maxn];
long long cost, flow, dis[maxn], h[maxn];
int g[300][300], t[11], c[11];

inline void add_edge(int from, int to, int cap, int dis)
{
	e[++e_num] = (edge) {head[from], to, cap, dis}; head[from] = e_num;
	e[++e_num] = (edge) {head[to], from,  0, -dis}; head[to]   = e_num;
}

std::queue<int> q;
void MinCostMaxFlow()
{
	std::fill(h + S, h + T + 1, 0);
	cost = flow = 0; int f = 1000000007;
	while(f)
	{
		std::fill(dis + S, dis + T + 1, LLONG_MAX >> 1); clear(vis, 0);
		dis[S] = 0, q.push(S);
		while(!q.empty())
		{
			int x = q.front(); q.pop();
			for(RG int i = head[x]; ~i; i = e[i].next)
			{
				int to = e[i].to, ds = e[i].dis + dis[x] + h[x] - h[to];
				if(e[i].cap > 0 && ds < dis[to])
				{
					dis[to] = ds, pre[to] = x, pre_e[to] = i;
					if(!vis[to]) vis[to] = 1, q.push(to);
				}
			}
			vis[x] = 0;
		}
		if(dis[T] == LLONG_MAX >> 1) return;
		for(RG int i = S; i <= T; i++) h[i] += dis[i];
		int cap = f;
		for(RG int i = T; i ^ S; i = pre[i])
			cap = std::min(cap, e[pre_e[i]].cap);
		f -= cap, flow += cap, cost += cap * h[T];
		for(RG int i = T; i ^ S; i = pre[i])
			e[pre_e[i]].cap -= cap, e[pre_e[i] ^ 1].cap += cap;
	}
}

int main()
{
	clear(head, -1); n = read(), m = read(); S = 0, T = n + m + 1;
	for(RG int i = 1; i <= m; i++)
		add_edge(i + n, n + m + 1, read(), 0);
	for(RG int i = 1; i <= n; i++)
		for(RG int j = 1; j <= m; j++)
			g[i][j] = read();
	for(RG int i = 1, x; i <= n; i++)
	{
		x = read();
		for(RG int j = 1; j <= x; j++) t[j] = read();
		for(RG int j = 1; j <= x + 1; j++) c[j] = read();
		for(RG int j = 1; j <= x; j++)
			add_edge(0, i, t[j] - t[j - 1], c[j]);
		add_edge(0, i, 1000000007, c[x + 1]);
		for(RG int j = 1; j <= m; j++)
			if(g[i][j]) add_edge(i, j + n, 1000000007, 0);
	}
	MinCostMaxFlow();
	printf("%lld\n", cost);
	return 0;
}
posted @ 2019-01-11 16:27  xgzc  阅读(125)  评论(0编辑  收藏  举报