现在的位置: 首页 > 综合 > 正文

ZOJ2539

2019年08月20日 ⁄ 综合 ⁄ 共 951字 ⁄ 字号 评论关闭

由于最大流是贴dinic模版的所以就只放主函数代码了,这题想了下,是个最小割,现求出每个\p[i]-v0\的和记为s1,然后对每个点\p[i]-v1\-\p[i]-v0\是它的权值,所有权值为负的点权值相反数之和为sum,如果这个是正的,那么就连这个点到汇点一条权值为这个的边,否则就从源点连条权值为这个相反数的边到这个店,然后对于每个点,连条到与之相邻的点一条边,权值是p[i]-p[j]的绝对值,然后最小割+s1-sum就是答案,仔细推敲下吧。

int main()
{
	int pro=0;
	scanf("%d",&T);
	while(T--)
	{
		sum=0;
		int s1=0;
		scanf("%d%d%d%d",&n,&m,&v0,&v1);
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				scanf("%d",&p[i][j]);
				s1+=abs(p[i][j]-v0);
			}
		s=n*m,t=s+1;
		dinic.init(s,t);
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				int nu=i*m+j;
				int mm=abs(p[i][j]-v1)-abs(p[i][j]-v0);
				if(mm<0)
					sum+=(-mm);
				if(mm>0)
					dinic.add_edge(nu,t,mm);
				else
					dinic.add_edge(s,nu,-mm);
			}
		for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			int nu=i*m+j;
			if(i>0)
				dinic.add_edge(nu,nu-m,abs(p[i][j]-p[i-1][j]));
			if(i<n-1)
				dinic.add_edge(nu,nu+m,abs(p[i][j]-p[i+1][j]));
			if(j>0)
				dinic.add_edge(nu,nu-1,abs(p[i][j]-p[i][j-1]));
			if(j<m-1)
				dinic.add_edge(nu,nu+1,abs(p[i][j]-p[i][j+1]));	
		}
		printf("Case %d:\n",++pro);
		printf("%d\n",s1+dinic.flow()-sum);
		if(T)
		puts("");
	}
	return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.