首页 > 代码库 > 【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)

【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)

题目模型出的真心神。

需要好难才能推出来。

本来打算写一篇好的题解,但是状态实在不好,没弄会这道题。

只能先扒建边留个坑了。


据说“单纯形算法”可以高速+裸建图 水过此题(呃,或曰此题乃单纯形裸题是也。)


前先给个链接吧,应该是目前网上最好的此题题解:

BYV大神的题解:www.byvoid.com/blog/noi-2008-employee/#more-916


我的代码:

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1050
#define M 30100
#define P 105
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
	int u,v,len,fee,next;
}e[M];
int head[N],cnt;
void add(int u,int v,int len,int fee)
{
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].fee=fee;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int s,t,dist[N];
int pre[N],lim[N];
bool in[N];
queue<int>q;
void spfa()
{
	memset(dist,0x3f,sizeof(dist));
	memset(lim,0,sizeof(lim));
	while(!q.empty())q.pop();
	int i,u,v;
	dist[s]=0,in[s]=1;
	lim[s]=inf;
	q.push(s);
	while(!q.empty())
	{
		u=q.front(),q.pop(),in[u]=0;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(!e[i].len)continue;
			if(dist[v]>dist[u]+e[i].fee)
			{
				dist[v]=dist[u]+e[i].fee;
				lim[v]=min(e[i].len,lim[u]);
				pre[v]=i;

				if(!in[v])
				{
					in[v]=1;
					q.push(v);
				}
			}
		}
	}
	return ;
}
void handle(int flow)
{
	for(int i=pre[t];i;i=pre[e[i].u])
	{
		e[i].len-=flow;
		e[i^1].len+=flow;
	}
}
int n,m,minfee;
int need[N];
int main()
{
//	freopen("test.in","r",stdin);
	int i,a,b,c;
	scanf("%d%d",&n,&m),n++;
	s=n+1,t=n+2,cnt=1;
	for(i=1;i<n;i++)scanf("%d",&need[i]);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		add(a,b+1,inf,c),add(b+1,a,0,-c);
	}
	for(i=1;i<=n;i++)
	{
		c=need[i]-need[i-1];
		if(c>=0)add(s,i,c,0),add(i,s,0,0);
		else add(i,t,-c,0),add(t,i,0,0);
		if(i>1)add(i,i-1,inf,0),add(i-1,i,0,0);
	}
	while(spfa(),dist[t]<inf)
	{
		minfee+=dist[t]*lim[t];
		handle(lim[t]);
	}
	printf("%d\n",minfee);
	return 0;
}
</span>


【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)