[HNOI2001] 소프트웨어 개발

최소 비용 및 최대 흐름

(나만의 드로잉 아이디어 프로세스 만 제공)
첫째, 포인트는 아침과 저녁, i와 n + i의 두 가지 포인트로 나뉩니다.
1. n + i에서 트래픽이 w [i]이고 비용이 0 인 에지까지. (어떤 방법을 사용하든 매일 w [i] 수건을 가지고 있어야 함을 의미합니다)
하루에 필요한 수건을 모으는 방법에는 새 수건을 직접 구입하거나 청소 한 후 두 가지 방법이 있습니다.
2. 새 타월을 구입하는 경우 : S에서 n + i 로의 흐름은 w [i]이고 비용은 f의 측면입니다.
3. 청소하면 i에서 n + i + a + 1 로의 흐름은 w [i]이고 비용은 fa의 측면이고 i에서 n + i + b + 1 로의 흐름은 w [i]입니다. , 비용은 fb의 측면입니다. (기껏해야 w [i] 타월이 있으며 하루 또는 b 일 후에 세탁하여 사용할 수 있습니다.)
4. 분명히 S와 i를 연결해야합니다. S에서 i 로의 흐름은 w [i]이고 비용은 0입니다.
이렇게 완성 된 것 같습니다. 그럼 20 점.
그런 다음 우리는 다음과 같은 문제를 발견했습니다. 하루 전에 많은 수건을 다 쓰고 청소 한 후에 i + a + 1 일 동안 청소하여 사용했는데 여전히 일부 수건이 남아 있으면이 수건을 i + a +에게 줄 수 없습니다. 1 + 1 일 동안 계속 사용하십니까?
5. n + i에서 n + i + 1까지, 흐름은 inf이고 비용은 0입니다. (여기 교통량은 inf입니다. 수건이 몇 장 있는지 모르기 때문입니다.)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+5,inf=2e9;
int n,a,b,f,fa,fb,w,s,t,mincost;
int d[N*2];
bool vis[N*2],ff[N*2];
int cnt=1,head[N*2];
struct edge{
    
    int next,to,w,dis;}e[N*12];
inline void add(int u,int v,int w,int dis)
{
    
    
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	e[cnt].w=w;;
	e[cnt].dis=dis;
	head[u]=cnt;
}
inline void insert(int u,int v,int w,int dis)
{
    
    
	add(u,v,w,dis); add(v,u,0,-dis);	
}

queue<int>q;
inline bool spfa()
{
    
    
	memset(d,60,sizeof(d));
	int maxn=d[0];
	memset(vis,false,sizeof(vis));
	d[s]=0; vis[s]=true; q.push(s);
	while (q.size())
	{
    
    
		int u=q.front(); q.pop();
		vis[u]=false;
		for (register int i=head[u]; i; i=e[i].next)
		if (e[i].w && d[e[i].to]>d[u]+e[i].dis)
		{
    
    
			d[e[i].to]=d[u]+e[i].dis;
			if (!vis[e[i].to]) q.push(e[i].to),vis[e[i].to]=true;	
		}
	}
	if (d[t]!=maxn) return true;
	return false;
}
int dfs(int u,int flow)
{
    
    
	if (u==t) return flow;
	int last=flow;
	ff[u]=true;
	for (register int i=head[u]; i; i=e[i].next)
	if (!ff[e[i].to] && e[i].w && d[e[i].to]==d[u]+e[i].dis)
	{
    
    
		int k=dfs(e[i].to,min(e[i].w,last));
		if (!k) {
    
    d[e[i].to]=-1; continue;}
		e[i].w-=k; e[i^1].w+=k;
		mincost+=e[i].dis*k;
		last-=k;
		if (!last) break;
	}
	return flow-last;
}
inline void dinic()
{
    
    
	while (spfa())
	{
    
    
		memset(ff,false,sizeof(ff));
		dfs(s,inf);
	}
}

signed main(){
    
    
	scanf("%lld%lld%lld%lld%lld%lld",&n,&a,&b,&f,&fa,&fb);
	s=0; t=2*n+1;
	for (register int i=1; i<=n; ++i)
	{
    
    
		scanf("%lld",&w);
		insert(n+i,t,w,0);
		//表示需要的毛巾量 
		insert(s,n+i,w,f);
		//方案一:购买新毛巾 
		insert(s,i,w,0); 
		if (i+a+1<=n) insert(i,n+i+a+1,inf,fa);
		if (i+b+1<=n) insert(i,n+i+b+1,inf,fb);
		//方案二:洗毛巾 
		if (i<n) insert(i,i+1,inf,0);
		//如果有需要,毛巾应该尽量尽早洗,所以之前洗完的毛巾,保存到后一天 
	}
	dinic(); 
	printf("%lld\n",mincost);
return 0;
}

추천

출처blog.csdn.net/Dove_xyh/article/details/108391022