[NOI2008] 志愿者招募

\(Solution\)

这是一道一个人覆盖一个区间的问题,对于人,考虑把他看成一流量,对于\(a_i\)的限制,相当于把\(a_i\)的流量放在了\(i\)点上,所以\(S\)\(1\)号点连\(inf\)\(n + 1\)号点和\(T\)\(inf\)\(i\)\(i + 1\)\(inf - a_i\)。对于留下的流量一定要产生费用并且用完还要归还,所以对于一个人覆盖的区间,\(s_i\)\(t_i + 1\)连一条\(inf\)流量,\(c_i\)费用的边,跑费用流即可。

\(Code\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 120005,inf = 2e9;
int h[N],S,T,n,flow[N],vis[N],q[N * 10],tot = 1,pre[N],up[N],m;
LL dis[N];

struct edge{
	int to,nxt,f,z;
}e[200005];
void add(int x,int y,int f,int z)
{
	e[++tot] = edge{y,h[x],f,z},h[x] = tot;
	e[++tot] = edge{x,h[y],0,-z},h[y] = tot;
}
int spfa()
{
	memset(flow,127,sizeof flow);
	memset(dis,50,sizeof dis);
	memset(vis,0,sizeof vis);
	int head = 0,tail = 1;
	q[1] = S,dis[S] = 0,vis[S] = 1,pre[T] = -1;
	while (head < tail)
	{
		int u = q[++head]; vis[u] = 0;
		for (int i = h[u]; i; i = e[i].nxt)
		{
			int v = e[i].to;
        	if (dis[v] > dis[u] + (LL)e[i].z && e[i].f > 0)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
			{
				dis[v] = dis[u] + (LL)e[i].z,pre[v] = u,up[v] = i;
				flow[v] = min(flow[u],e[i].f);
				if (!vis[v]) q[++tail] = v,vis[v] = 1; 
			}
		}
	}
	return (pre[T] != -1);
}
int main()
{
	scanf("%d%d",&n,&m);
	S = n + 2,T = S + 1,add(S,1,inf,0),add(n + 1,T,inf,0);
	for (int i = 1,q; i <= n; i++) scanf("%d",&q),add(i,i + 1,inf - q,0);
	for (int i = 1,q,p,c; i <= m; i++)
		scanf("%d%d%d",&q,&p,&c),add(q,p + 1,inf,c);
	LL ansc = 0;
	for (; spfa();)
	{
		int o = T; ansc += (LL)flow[T] * dis[T];
		for (; o != S; o = pre[o]) e[up[o]].f -= flow[T],e[up[o] ^ 1].f += flow[T];
	}
	printf("%lld\n",ansc);
}
posted @ 2022-01-25 20:12  RiverSheep  阅读(31)  评论(0)    收藏  举报