标签:
题意:
给出一个R*P*Q的三维点阵,求一个函数f(x,y) (1<=x<=P,1<=y<=Q);
使∑v[f(x,y)][x][y]最小,且相邻两个f值之差不超过D;
R,P,Q<=40,v<=1000;
题解:
看起来就好神的题,然而就算告诉我是网络流我也不信能跑64000个点;
不过事实上= =,数据中最大是30 30 30的。。所以结果大家跑的都很快;
这道题的建图就是首先限制在一行只能选择一个,那么从上向下连出一条链,每个弧的流量都是对应点的权值;
如果不考虑D的影响,对这个求最小割得到的就是答案啦;
为了加入D这个条件,我们对于每个点再向它四周比他高D的点连一条流量为INF的边;
这样之后一定还能保证每个(x,y)一定是一个割边,因为假设一个(x,y)有两个割边;
那么一定有一个流进入到它们中间,否则下面的割边没有意义;
而因为如果上面的割边有意义,那么一定是为了防止一个从他们中间出发向上的流;
实际上这样防止是没有用的,因为那个流入它们中间的流可以向上流走;
所以这种情况不可能存在,那么根据这个结论,一个合法的个割集也就一定满足D的条件了;
时间复杂度呵呵;
代码:
#include<queue> #include<stdio.h> #include<string.h> #include<algorithm> #define N 50 #define PT 70000 #define M 1000000 using namespace std; int P,Q,R,D; int next[M],to[M],flow[M],head[PT],ce=1; int dis[PT],S,T; int v[N][N][N],num[N][N][N],tot; queue<int>q; void add(int x,int y,int fl) { to[++ce]=y; next[ce]=head[x]; flow[ce]=fl; head[x]=ce; to[++ce]=x; next[ce]=head[y]; flow[ce]=0; head[y]=ce; } void add(int x,int y) { to[++ce]=y; next[ce]=head[x]; flow[ce]=0x3f3f3f3f; head[x]=ce; to[++ce]=x; next[ce]=head[y]; flow[ce]=0; head[y]=ce; } bool BFS() { memset(dis,0,sizeof(dis)); q.push(S); dis[S]=1; int x,i; while(!q.empty()) { x=q.front(),q.pop(); for(i=head[x];i;i=next[i]) { if(flow[i]&&!dis[to[i]]) { dis[to[i]]=dis[x]+1; q.push(to[i]); } } } return dis[T]!=0; } int dfs(int x,int lim) { if(x==T) return lim; int i,ret,temp; for(i=head[x],ret=0;i;i=next[i]) { if(flow[i]&&dis[to[i]]==dis[x]+1) { temp=dfs(to[i],min(flow[i],lim-ret)); flow[i]-=temp,flow[i^1]+=temp; ret+=temp; if(lim==ret) return ret; } } if(!ret) dis[x]=0; return ret; } int main() { int i,j,k,x,y,ans; scanf("%d%d%d%d",&P,&Q,&R,&D); for(i=1;i<=R;i++) { for(j=1;j<=P;j++) { for(k=1;k<=Q;k++) { scanf("%d",&v[i][j][k]); num[i][j][k]=++tot; } } } S=tot+1,T=tot+2; for(i=1;i<=R;i++) { for(j=1;j<=P;j++) { for(k=1;k<=Q;k++) { if(i==1) add(S,num[i][j][k],v[i][j][k]); else add(num[i-1][j][k],num[i][j][k],v[i][j][k]); if(i==R) add(num[i][j][k],T); if(i>D) { if(j!=1) add(num[i][j][k],num[i-D][j-1][k]); if(j!=P) add(num[i][j][k],num[i-D][j+1][k]); if(k!=1) add(num[i][j][k],num[i-D][j][k-1]); if(k!=Q) add(num[i][j][k],num[i-D][j][k+1]); } } } } ans=0; while(BFS()) ans+=dfs(S,0x3f3f3f3f); printf("%d\n",ans); return 0; }
标签:
原文地址:http://blog.csdn.net/ww140142/article/details/50085961