码迷,mamicode.com
首页 > 其他好文 > 详细

网络流 24 题 解题报告

时间:2020-06-08 19:11:58      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:最小割   网络   要求   queue   线性规划   容量   展开   scan   head   

刚开始觉得 24 题都是板子,不屑于写题解,结果第 6 道就教我做人了……orz
按照惯例,“机器人路径规划问题”是假题,不写。
另外,网络流 24 题的全称是“网络流与线性规划 24 题”,所以里面有些题不需要网络流也可以解决,怎么简单怎么来。
约定:用有序对 \((cap,cost)\) 表示这条边的容量与费用。


飞行员配对方案问题

裸二分图匹配。

软件补丁问题

状压+最短路。水题。

孤岛营救问题

裸的 BFS。

负载平衡问题

环形均分纸牌,有贪心的结论,不展开说了。

方格取数问题

要求最大值,考虑用总和减去互斥最小值,套路地按坐标奇偶性建出二分图的流量网络,互斥的点之间建容量为 INF 的边,跑最小割即可。

餐巾计划问题

出师不利啊……才做了几题就趴下了……
首先必须想到的是把一天拆成起始点和结束点两个,起始点用来接收新的纸巾,结束点用来决策脏纸巾的去向。
一个显然的连边是 \(S\) 到每天的起始点连 \((\infty,p)\),代表买纸巾的操作。对于快(慢)洗,需要从 \(i\) 点的结束点向 \(i+m\)(或 \(i+n\))的起始点连边,这个也是比较简单的。
然后是两个比较反直觉的连边:\(S\)\(i\) 的结束点连 \((r_i,0)\)\(i\) 的起始点向 \(T\)\((r_i,0)\)
感性理解一下,每天的终止点只会由源点与前一天的终止点连接,保证每天的纸巾处理量(也就是向以后留的纸巾)达到要求,起始点向汇点链接保证了每天的纸巾需求量达到要求。
ps:如果想要不那么反直觉地做这道题,可以用上下界最小费用可行流做。
这题还是得放放代码:

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

const int N=2005,INF=0x3f3f3f3f;
struct Edge{int to,nxt,c,w;}e[N*N>>1];
int head[N<<1],cnt=1,n,r[N],p,d1,f,d2,s;
int incf[N<<1],S,T,pre[N<<1],inq[N<<1],dis[N<<1];
ll ans;
queue<int> q;

inline void add(int u,int v,int c,int w)
{
	e[++cnt]=(Edge){v,head[u],c,w};head[u]=cnt;
	e[++cnt]=(Edge){u,head[v],0,-w};head[v]=cnt;
}

bool spfa()
{
	q.push(S);
	for(int i=1;i<=T;++i) dis[i]=INF;
	incf[S]=INF,dis[S]=0;
	while(!q.empty())
	{
		int u=q.front(); inq[u]=0; q.pop();
		for(int i=head[u],v;i;i=e[i].nxt)
			if(e[i].c&&dis[v=e[i].to]>dis[u]+e[i].w)
			{
				dis[v]=dis[u]+e[i].w; pre[v]=i;
				incf[v]=min(incf[u],e[i].c);
				if(!inq[v]) inq[v]=1,q.push(v);
			}
	}
	return dis[T]!=INF;
}

void upd()
{
	int x=T;
	while(x!=S)
	{
		int i=pre[x];
		e[i].c-=incf[T],e[i^1].c+=incf[T];
		x=e[i^1].to;
	}
	ans+=1LL*dis[T]*incf[T];
}

int main()
{
	scanf("%d",&n); S=n*2+1; T=S+1;
	for(int i=1;i<=n;++i)
	{
		scanf("%d",r+i);
		add(S,i,r[i],0); add(i+n,T,r[i],0);
	}
	scanf("%d%d%d%d%d",&p,&d1,&f,&d2,&s);
	for(int i=1;i<=n;++i)
	{
		add(S,i+n,INF,p);
		if(i<n) add(i,i+1,INF,0);
		if(i+d1<=n) add(i,i+n+d1,INF,f);
		if(i+d2<=n) add(i,i+n+d2,INF,s);
	}
	while(spfa()) upd();
	printf("%lld",ans);
	return 0;
}

网络流 24 题 解题报告

标签:最小割   网络   要求   queue   线性规划   容量   展开   scan   head   

原文地址:https://www.cnblogs.com/wzzyr24/p/13067489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!