BOJ313 Candy [网络流 dinic]

链接:

http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=313


题意:

给定一个50*50的矩阵,矩阵中每个格子代表一个孩子手中的糖果。

每个孩子可以向上下左右相邻的孩子传递至多一个糖果。


提前:

注意题意中的“至多”,很多“至多'问题都可以应用网络流来解决。

之前一直写的dinic模板过不了,之前的dinic模板是bfs进行分层【level[v]=level[now]+1】。

但是这个构图和以前的不同,每个点到源点和汇点都有直接相邻。

所以可以直接省略bfs这个步骤。【如果不省略bfs这个步骤,就一直tle不停的tle直到天荒地老】


#include<iostream>
#include<fstream>
#include<map>
#include<vector>
#include<string>
#include<memory.h>
#include<cmath>
#include<algorithm>
#include<queue>
#define Min(a,b) (a<b?a:b)
#define Max(a,b) (a>b?a:b)
#define Abs(a) (a>0?(a):-(a))
#define llong long long int
using namespace std;
const int N=55,M=2505,inf=0x7fffffff;
int n,m;
int mat[N][N];
struct Edge
{
	int v;
	int w;
	int next;
}edge[M*20];
int edgehead[M];
int s,t;
int mx[4]={-1,1,0,0};
int my[4]={0,0,-1,1};
int k=1;
bool vis[M];
void insert(int u,int v,int w)
{
	edge[++k].v=v;
	edge[k].w=w;
	edge[k].next = edgehead[u];
	edgehead[u]=k;
	edge[++k].v=u;
	edge[k].w=0;
	edge[k].next=edgehead[v];
	edgehead[v]=k;
}
int dinic(int now,int mi)
{

	if(now==t)
	  return mi;
	vis[now]=true;
	int sum=0;
	for(int i = edgehead[now];i && sum<mi;i=edge[i].next)
	{
		int v = edge[i].v;
		int w = edge[i].w;
		if(!vis[v]&&w)
		{
			int ret=dinic(v,Min(w,mi-sum));
			edge[i].w -= ret;
			edge[i^1].w +=ret;
			sum+=ret;
		}
	}
	return sum;
}
int solve()
{
	int ret=0,sum=0;
	memset(vis,0,sizeof(vis));
	while(ret=dinic(s,inf))
	{
		sum+=ret;
		memset(vis,0,sizeof(vis));
	}
	return sum;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(edge,0,sizeof(edge));
		memset(edgehead,0,sizeof(edgehead));
		k=1;
		s = n*m;
		t = s+1;
		int sum=0;
		for(int i =0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				scanf("%d",mat[i]+j);
				sum+=mat[i][j];
			}
		}
		if(sum%(n*m))
		{
			printf("NO\n");
			continue;
		}
		int avg = sum/(n*m);
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				insert(s,i*m+j,mat[i][j]);
				insert(i*m+j,t,avg);
			}
		for(int i =0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				for(int k=0;k<4;k++)
				{
					int ii = i+my[k];
					int jj = j+mx[k];
					if(ii>=0&&ii<n&&jj>=0&&jj<m)
					{
						insert(i*m+j,ii*m+jj,1);
					}
				}
			}
		}
		
		if(sum==solve())
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
	}
	return 0;
}


你可能感兴趣的:(BOJ313 Candy [网络流 dinic])