• 【HNOI2013】切糕


    题面

    题解

    新建第(R + 1)层,将切点换成割边,然后就出现了最小割模型

    然后从源点(S)向第一层的每个点连一条容量为(infty)的边,从第(R + 1)层的每个点向汇点(T)连一条容量为(infty)的边,这些边不会被割掉。

    首先不考虑(D)的限制,从((i, j, k) o (i, j, k + 1))连一条容量为(val[i][j][k])的边。

    然后考虑(D)的限制,假设((i, j))((k, l))是相邻的,那么我们要让(f(i, j) - f(k, l) > D)时也能有从(S o T)的流,

    那么从((i, j, z))((k, l, z - D))连一条容量为(infty)的边就可以了

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (!isdigit(ch))) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(250010), maxm(1000000), N(45), INF(0x3f3f3f3f);
    const int dx[] = {0, 1, 0, -1};
    const int dy[] = {1, 0, -1, 0};
    
    int P, Q, R, D, idcnt;
    int val[N][N][N];
    int id[N][N][N];
    
    struct edge { int next, to, cap; } e[maxm];
    int head[maxn], e_num = -1, S, T;
    
    inline void add_edge(int from, int to, int cap)
    {
    	e[++e_num] = (edge) {head[from], to, cap}; head[from] = e_num;
    	e[++e_num] = (edge) {head[to], from,  0 }; head[to]   = e_num;
    }
    
    int q[maxn], tail, lev[maxn], cur[maxn];
    int bfs()
    {
    	memset(lev, 0, sizeof lev); q[tail = lev[S] = 1] = S;
    	for(RG int i = 1; i <= tail; i++)
    	{
    		int x = q[i];
    		for(RG int j = head[x]; ~j; j = e[j].next)
    		{
    			int to = e[j].to;
    			if(lev[to] || (!e[j].cap)) continue;
    			q[++tail] = to, lev[to] = lev[x] + 1;
    		}
    	}
    	return lev[T];
    }
    
    int dfs(int x, int f)
    {
    	if(x == T || (!f)) return f;
    	int ans = 0, cap;
    	for(RG int &i = cur[x]; ~i; i = e[i].next)
    	{
    		int to = e[i].to;
    		if(e[i].cap && lev[to] == lev[x] + 1)
    		{
    			cap = dfs(to, std::min(f - ans, e[i].cap));
    			e[i].cap -= cap, e[i ^ 1].cap += cap, ans += cap;
    			if(ans == f) break;
    		}
    	}
    	if(!ans) lev[x] = 0;
    	return ans;
    }
    
    inline int Dinic()
    {
    	int ans = 0;
    	while(bfs())
    	{
    		for(RG int i = S; i <= T; i++) cur[i] = head[i];
    		ans += dfs(S, INF);
    	}
    	return ans;
    }
    
    int main()
    {
    	memset(head, -1, sizeof head); S = ++idcnt;
    	P = read(), Q = read(), R = read(), D = read();
    	for(RG int k = 1; k <= R; k++)
    		for(RG int i = 1; i <= P; i++)
    			for(RG int j = 1; j <= Q; j++)
    				val[i][j][k] = read();
    	for(RG int i = 1; i <= P; i++)
    		for(RG int j = 1; j <= Q; j++)
    			for(RG int k = 1; k <= R + 1; k++)
    				id[i][j][k] = ++idcnt;
    	T = ++idcnt;
    	for(RG int i = 1; i <= P; i++)
    		for(RG int j = 1; j <= Q; j++)
    			add_edge(S, id[i][j][1], INF),
    			add_edge(id[i][j][R + 1], T, INF);
    	for(RG int i = 1; i <= P; i++)
    		for(RG int j = 1; j <= Q; j++)
    			for(RG int k = 1; k <= R; k++)
    				add_edge(id[i][j][k], id[i][j][k + 1], val[i][j][k]);
    	for(RG int i = 1; i <= P; i++)
    		for(RG int j = 1; j <= Q; j++)
    			for(int d = 0; d < 4; d++)
    			{
    				int tx = dx[d] + i, ty = dy[d] + j;
    				if(tx < 1 || tx > P || ty < 1 || ty > Q) continue;
    				for(RG int k = D + 1; k <= R + 1; k++)
    					add_edge(id[i][j][k], id[tx][ty][k - D], INF);
    			}
    	printf("%d
    ", Dinic());
    	return 0;
    }
    
  • 相关阅读:
    JAVA面试问题与解答(1-15)
    17个经典的Spring面试问答
    Linux下载——下载文件的命令
    MySQL入门——在Linux下安装和卸载MySQL
    MySQL入门——在Linux下安装和卸载MariaDB
    MySQL入门——MySQL数据库和SQL语言
    Linux性能分析——分析系统性能相关的命令
    Linux网络——查看网络连接情况的命令
    Linux网络——配置网络之iproute家族命令
    Linux网络——配置网络之ifconfig家族命令
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10395951.html
Copyright © 2020-2023  润新知