zoukankan      html  css  js  c++  java
  • 【nowcoder 225285】牛牛防疫情(网络流)

    牛牛防疫情

    题目链接:nowcoder 225285

    题目大意:

    ——>点我跳转<——

    题目大意

    给你一个二维网格图,然后有一些特殊点,它每隔一个时刻让它四边的点变成特殊点。
    然后你可以在两个点之间建一个屏障使得无法转变。
    然后使得一个普通点变成特殊点要费用 c,建立屏障是要 1 费用。
    要你最小化总费用。

    思路

    这道题我们考虑用网络流来做。

    这么一想之后你就会发现这题确实可以网络流。
    相当于搞最小割,所有点向汇点连边流量是 (c) 表示被感染,然后本身被感染的点连向源点流量 INF 表示被感染。然后点和它四边之间连边流量是 (1) 表示要建护栏。

    然后跑最小割就是答案。

    代码

    #include<map>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    #define INF 1000000000
    
    using namespace std;
    
    struct node {
    	int x, to, nxt;
    }e[500004];
    int n, m, x, y, le[50001], KK, dis[50001], S, T, lee[50001];
    int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
    int ans, c;
    
    void add(int x, int y, int z) {
    	e[++KK] = (node){z, y, le[x]}; le[x] = KK;
    	e[++KK] = (node){0, x, le[y]}; le[y] = KK;
    }
    
    int get_nm(int x, int y) {
    	return (x - 1) * n + y;
    }
    
    bool bfs() {//网络流
    	queue <int> q;
    	memcpy(lee, le, sizeof(lee));
    	memset(dis, 0x7f, sizeof(dis));
    	dis[S] = 0;
    	q.push(S);
    	int now;
    	while (!q.empty()) {
    		now = q.front();
    		q.pop();
    		
    		for (int i = le[now]; i; i = e[i].nxt)
    			if (e[i].x && dis[e[i].to] > dis[now] + 1) {
    				dis[e[i].to] = dis[now] + 1;
    				q.push(e[i].to);
    			}
    	}
    	return dis[T] < INF;
    }
    
    int dfs(int now, int sum) {
    	if (now == T) return sum;
    	int go = 0, this_go;
    	for (int i = lee[now]; i; i = e[i].nxt) {
    		lee[now] = i;
    		if (e[i].x && dis[e[i].to] == dis[now] + 1) {
    			this_go = dfs(e[i].to, min(e[i].x, sum - go));
    			if (this_go) {
    				e[i].x -= this_go;
    				e[i ^ 1].x += this_go;
    				go += this_go;
    				if (go == sum) return go;
    			}
    		}
    	}
    	return go;
    }
    
    void dinic() {
    	while (bfs()) {
    		ans += dfs(S, INF);
    	}
    }
    
    int main() {
    	KK = 1;
    	scanf("%d %d %d", &n, &m, &c);
    	
    	S = 50000 - 1; T = 50000 - 2;
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d", &x, &y); x++; y++;
    		add(S, get_nm(x, y), INF);
    	}
    	
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++) {
    			add(get_nm(i, j), T, c);
    			
    			for (int k = 0; k < 4; k++) {
    				x = i + dx[k]; y = j + dy[k];
    				if (1 <= x && x <= n && 1 <= y && y <= n) {//可以建屏障
    					add(get_nm(i, j), get_nm(x, y), 1);
    				}
    			}
    		}
    	
    	dinic();
    	printf("%d", ans - c * m);//记得减去本身就已经感染的点
    	
    	return 0;
    }
    
  • 相关阅读:
    一个浏览器循环刷新网页的例子
    Ajax和JSON基础
    HTML-第三章构建模块小结
    HTML-元素属性
    入前端坑的第一天
    JZOJ 【2021.11.10NOIP提高组联考】
    LG P2633 Count on a tree
    JZOJ 7339.改试卷
    [CEOI2017] Building Bridges
    拉格朗日插值法
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/nowcoder_225285.html
Copyright © 2011-2022 走看看