3144: [Hnoi2013]切糕
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2422 Solved: 1317
[Submit][Status][Discuss]
Description
Input
第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。
100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。
Output
仅包含一个整数,表示在合法基础上最小的总不和谐值。
Sample Input
2 2 2
1
6 1
6 1
2 6
2 6
1
6 1
6 1
2 6
2 6
Sample Output
6
HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
Source
考虑网络流如何实现,题目大意就是把一个长方体延顶点切成两半。。。估计最小割,那么最大流求解,考虑到这个题目是根据点权实现,所以考虑拆点割点。至于题目中的第二个限制,发现了说白了就这么个事,对于一个点前后左右的点,另一层的割点与它的高度差不能超过d,其实还是看了眼题解才明白它到底想表达个什么意思。
具体实现了之后发现不可行。。。。原因就是,割不干净,总会剩下几条本来不应该可行的通路。
所以换个思路,我们不拆点了,转而增加一层新的虚拟层,把每层的点向下一层这个位置的点连接不和谐值得边,然后就可以A掉了。还没看明白就自己画图。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define re register #define inf 400000000 using namespace std; int n,s,q,dis[2000011],t,l,cur[200051]; struct po { int nxt,to,w; }edge[3000021]; int head[70151],tot,dep[70001],map[41][41][41],nm[41][41][41],id,d,num=-1; int x,y,m; int dx[5]={0,0,1,0,-1}; int dy[5]={0,1,0,-1,0}; inline int read() { int x=0,c=1; char ch=' '; while((ch>'9'||ch<'0')&&ch!='-')ch=getchar(); while(ch=='-')c*=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x*c; } inline void add_edge(int from,int to,int w) { edge[++num].nxt=head[from]; edge[num].to=to; edge[num].w=w; head[from]=num; } inline void add(int from,int to,int w) { add_edge(from,to,w); add_edge(to,from,0); } inline bool bfs() { memset(dep,0,sizeof(dep)); queue<int> q; while(!q.empty()) q.pop(); q.push(s); dep[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(re int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(dep[v]==0&&edge[i].w>0) { dep[v]=dep[u]+1; if(v==t) return 1; q.push(v); } } } return 0; } inline int dfs(int u,int dis) { if(u==t) return dis; int diss=0; for(re int& i=cur[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].w!=0&&dep[v]==dep[u]+1) { int check=dfs(v,min(dis,edge[i].w)); if(check>0) { dis-=check; diss+=check; edge[i].w-=check; edge[i^1].w+=check; if(dis==0) break; } } } return diss; } inline int dinic() { int ans=0; while(bfs()) { for(re int i=0;i<=t;i++) cur[i]=head[i]; while(int d=dfs(s,inf)) ans+=d; } return ans; } int main() { memset(head,-1,sizeof(head)); int P,Q,R; cin>>P>>Q>>R; cin>>d; s=0; for(re int k=1;k<=R;k++) for(re int i=1;i<=P;i++) for(re int j=1;j<=Q;j++) { map[k][i][j]=read(); } for(re int k=1;k<=R+1;k++) for(re int i=1;i<=P;i++) for(re int j=1;j<=Q;j++) { nm[k][i][j]=++id; } t=id+1; for(re int k=1;k<=R;k++) for(re int i=1;i<=P;i++) for(re int j=1;j<=Q;j++) add(nm[k][i][j],nm[k+1][i][j],map[k][i][j]); for(re int i=1;i<=P;i++) for(re int j=1;j<=Q;j++) { add(s,nm[1][i][j],inf); add(nm[R+1][i][j],t,inf); } for(re int k=d+1;k<=R;k++) for(re int i=1;i<=P;i++) for(re int j=1;j<=Q;j++) { for(re int h=1;h<=4;h++) { int lx=i+dx[h]; int ly=j+dy[h]; if(lx>=1&&lx<=P&&ly>=1&&ly<=Q) { add(nm[k][i][j],nm[k-d][lx][ly],inf); } } } int tot=dinic(); cout<<tot; }