ZOJ2539

来源:互联网 发布:网络助学贷款 编辑:程序博客网 时间:2024/05/17 04:55
由于最大流是贴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);elsedinic.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;}

原创粉丝点击