zoukankan      html  css  js  c++  java
  • bzoj3894 文理分科

    题目链接

    思路

    先将题目转化为求最小割。也就是要找出一些贡献不选,使得这些贡献的和最小。
    对于单个点的贡献。显然我们可以从(S)到这个点连一条容量为选文收益的边。从这个点到(T)连一条容量为选理收益的边。
    然后考虑哪些额外的贡献。只要相邻的这(5)个点中有任何一个不选文,那么这个集合选文的额外贡献就没有了。所以就新建一个点。然后从新建的这个点向这个集合中的(5)个点各连一条容量为(INF)的边,然后从(S)向这个新建的点连一条容量为贡献的边。对于理科同理。
    然后跑一遍最小割,用总收益减去最小割即可。

    代码

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<ctime>
    #include<bitset>
    using namespace std;
    typedef long long ll;
    #define NUM(x,y) y + (x - 1) * m
    const int N = 100000 + 10,M = 1000000 + 10,INF = 1e9;
    #define change(x) x & 1 ? x + 1 : x - 1
    int dx[5] = {0,1,0,-1,0};
    int dy[5] = {0,0,1,0,-1};
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    struct node {
    	int v,w,nxt;
    }e[M];
    int head[N],ejs;
    void add(int u,int v,int w) {
    	e[++ejs].v = v;e[ejs].w = w;e[ejs].nxt = head[u];head[u] = ejs;
    	e[++ejs].v = u;e[ejs].w = 0;e[ejs].nxt = head[v];head[v] = ejs;
    }
    int dep[N];
    int S,T;
    int dfs(int u,int now) {
    	if(u == T) return now;
    	int ret = 0;
    	for(int i = head[u];i;i = e[i].nxt) {
    		int v = e[i].v;
    		if(dep[v] != dep[u] + 1 || e[i].w <= 0) continue;
    		int k = dfs(v,min(now - ret,e[i].w));
    		ret += k;
    		e[i].w -= k;
    		e[change(i)].w += k;
    		if(ret == now) return ret;
    	}
    	return ret;
    }
    queue<int>q;
    int bfs() {
    	while(!q.empty()) q.pop();
    	memset(dep,0,sizeof(dep));
    	dep[S] = 1;
    	q.push(S);
    	while(!q.empty()) {
    		int u = q.front();q.pop();
    		for(int i = head[u];i;i = e[i].nxt) {
    			int v = e[i].v;
    			if(dep[v] || e[i].w <= 0) continue;
    			dep[v] = dep[u] + 1;
    			q.push(v);
    			if(v == T) return 1;
    		}
    	}
    	return 0;
    }
    int dinic() {
    	int ret = 0;
    	while(bfs()) 
    		ret += dfs(S,INF);
    	return ret;
    }
    int main() {
    	int ans = 0;
    	int n = read(),m = read();
    	S = n * m * 3 + 1;T = S + 1;
    	for(int i = 1;i <= n;++i) {
    		for(int j = 1;j <= m;++j) {
    			int w = read();
    			ans += w;
    			add(S,NUM(i,j),w);
    		}
    	}
    	for(int i = 1;i <= n;++i) {
    		for(int j = 1;j <= m;++j) {
    			int w = read();
    			ans += w;
    			add(NUM(i,j),T,w);
    		}
    	}
    	for(int i = 1;i <= n;++i) {
    		for(int j = 1;j <= m;++j) {
    			int w = read();
    			ans += w;
    			for(int k = 0;k <= 4;++k) {
    				int x = i + dx[k],y = j + dy[k];
    				if(x > n || y > m || x < 1 || y < 1) continue;
    				add(NUM(i,j) + n * m,NUM(x,y),INF);
    			}
    			add(S,NUM(i,j) + n * m,w);
    		}
    	}
    	for(int i = 1;i <= n;++i) {
    		for(int j = 1;j <= m;++j) {
    			int w = read();
    			ans += w;
    			for(int k = 0;k <= 4;++k) {
    				int x = i + dx[k],y = j + dy[k];
    				if(x > n || y > m || x < 1 || y < 1) continue;
    				add(NUM(x,y),NUM(i,j) + n * m * 2,INF);
    			}
    			add(NUM(i,j) + n * m * 2,T,w);
    		}
    	}
    	cout<<ans - dinic();
    	return 0;
    }
    
  • 相关阅读:
    微信小程序开发——修改小程序原生checkbox、radio默认样式
    微信小程序开发——微信小程序下拉刷新真机无法弹回
    转:slf4j-api、slf4j-log4j12、log4j之间关系
    MyBatis3 入门学习指南
    Java 多线程重排序的探究
    Kafka 生产者和消费者入门代码基础
    Java面试题
    刻苦读书的故事合集
    Win10 calc.exe 无法打开计算器的解决方法
    Redis(三):set/get 命令源码解析
  • 原文地址:https://www.cnblogs.com/wxyww/p/10355599.html
Copyright © 2011-2022 走看看