• BZOJ3144: [Hnoi2013]切糕


    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

    Sample Output

    6

    HINT

    最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1

     
    考虑用最小割来做,我们可以这样建图:
    对于每一个格子(i,j),将S向(i,j,1)连条容量为A[i][j][1]的边,将(i,j,r)向T连条容量为inf的边,(i,j,k-1)向(i,j,k)连一条容量为A[i][j][k]的边。
    那么这条链上的割就代表选了一个f(i,j)。
    如果加上D的限制,考虑两个相邻格子(i,j)和(i`,j`),从(i,j,k+D)向(i`,j`,k)连一条容量为inf的边,从(i`,j`,k+D)向(i,j,k)连一条容量为inf的边,意为如果f[i][j]选了k+D,那么f[i`][j`]肯定要>=k,且如果f[i`][j`]选了k+D,那么f[i][j]肯定要>=k,解出f[i`][j`]-D<=f[i][j]<=f[i`][j`]+D且f[i][j]-D<=f[i`][j`]<=f[i][j]+D,恰好满足题意。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
    	if(head==tail) {
    		int l=fread(buffer,1,BufferSize,stdin);
    		tail=(head=buffer)+l;
    	}
    	return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=70010;
    const int maxm=1000010;
    struct Dinic {
    	int n,m,s,t,clo;
    	int first[maxn],next[maxm];
    	int cur[maxn],vis[maxn],d[maxn];
    	struct Edge {int from,to,flow;}edges[maxm];
    	void init(int n) {
    		this->n=n;m=0;
    		memset(first,-1,sizeof(first));
    	}
    	void AddEdge(int u,int v,int w) {
    		edges[m]=(Edge){v,u,0};next[m]=first[v];first[v]=m++;
    		edges[m]=(Edge){u,v,w};next[m]=first[u];first[u]=m++;
    	}
    	int Q[maxn];
    	int BFS() {
    		int l=1,r=1;Q[r++]=s;vis[s]=++clo;
    		while(l!=r) {
    			int x=Q[l++];cur[x]=first[x];
    			ren {
    				Edge& e=edges[i];
    				if(e.flow&&vis[e.to]!=clo) {
    					vis[e.to]=clo;
    					d[e.to]=d[x]+1;
    					Q[r++]=e.to;
    				}
    			}
    		}
    		return vis[t]==clo;
    	}
    	int DFS(int x,int a) {
    		if(x==t||!a) return a;
    		int flow=0,f;
    		for(int& i=cur[x];i!=-1;i=next[i]) {
    			Edge& e=edges[i];
    			if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))) {
    				e.flow-=f;edges[i^1].flow+=f;
    				flow+=f;a-=f;if(!a) break;
    			}
    		}
    		return flow;
    	}
    	int solve(int s,int t) {
    		this->s=s;this->t=t;int flow=0;
    		while(BFS()) flow+=DFS(s,1e9);
    		return flow;
    	}
    }sol;
    int n,m,r,d,A[45][45][45];
    int id(int i,int j,int k) {return (k-1)*n*m+(i-1)*m+j;}
    const int mx[]={1,-1,0,0};
    const int my[]={0,0,1,-1};
    int main() {
    	n=read();m=read();r=read();d=read();
    	int S=n*m*r+1,T=n*m*r+2;sol.init(T);
    	rep(i,1,r) rep(j,1,n) rep(k,1,m) A[j][k][i]=read();
    	rep(i,1,n) rep(j,1,m) rep(k,1,r) {
    		if(k==1) sol.AddEdge(S,id(i,j,k),A[i][j][k]);
    		else sol.AddEdge(id(i,j,k-1),id(i,j,k),A[i][j][k]);
    		if(k==r) sol.AddEdge(id(i,j,k),T,1e9);
    		if(k>d) rep(dir,0,3) {
    			int nx=i+mx[dir],ny=j+my[dir];
    			if(nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(i,j,k),id(nx,ny,k-d),1e9);
    		}
    	}
    	printf("%d
    ",sol.solve(S,T));
    	return 0; 
    }
    

      

  • 相关阅读:
    JS
    JS
    JS
    CSS
    CSS
    CSS
    NPOI导出自动换行效果
    Httpcookie的简单应用
    前台JS设置Cookies后台读取刚设置的Cookies
    SQL SERVER 如何调试存储过程
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5330206.html
Copyright © 2020-2023  润新知