zoukankan      html  css  js  c++  java
  • 【洛谷 P2472】 [SCOI2007]蜥蜴 (最大流)

    题目链接
    简单网络流。
    源点向蜥蜴连流量为(1)的边。
    能跳出去的点向汇点连流量为(INF)的边。
    把每个点拆成(2)个点,(O(n^4))枚举两两点,如果距离小于等于(d),就互连流量为(INF)的边。
    然后跑(dinic)就行了。

    #include <cstdio>
    #include <queue>
    #include <cmath>
    #include <cstring>
    #define INF 2147483647
    using namespace std;
    const int N = 25;
    const int MAXN = 100010;
    const int MAXM = 200010;
    inline int read(){
        int s = 0, w = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); }
        return s * w;
    }
    struct Edge{
        int next, to, rest;
    }e[MAXM];
    int s, t, num = 1, n, m, d;
    int head[MAXN];
    char ch;
    inline void Add(int from, int to, int flow){
        e[++num] = (Edge){ head[from], to, flow }; head[from] = num;
        e[++num] = (Edge){ head[to], from, 0 }; head[to] = num;
    }
    int level[MAXN], now, tot, h[N][N];
    queue <int> q;
    int re(){
    	memset(level, 0, sizeof level);
        while(q.size()) q.pop();
        q.push(s); level[s] = 1;
        while(q.size()){
          now = q.front(); q.pop();
          for(int i = head[now]; i; i = e[i].next)
             if(e[i].rest && !level[e[i].to]){
               level[e[i].to] = level[now] + 1;
               q.push(e[i].to);
             }
        }
        return level[t];
    }
    int findflow(int u, int flow){
    	if(!flow || u == t) return flow;
    	int f = 0, t;
    	for(int i = head[u]; i; i = e[i].next){
    		if(e[i].rest && level[e[i].to] == level[u] + 1){
    			f += (t = findflow(e[i].to, min(flow - f, e[i].rest)));
    			e[i].rest -= t; e[i ^ 1].rest += t;
    		}
    	}
    	if(!f) level[u] = 0;
    	return f;
    }
    int dinic(){
        int ans = 0;
        while(re())
          ans += findflow(s, INF);
        return ans;
    }
    inline int r(int i, int j){
    	return (i - 1) * m + j;
    }
    inline int c(int i, int j){
    	return r(i, j) + 10000;
    }
    inline double dis(int i, int j, int k, int l){
    	return sqrt((k - i) * (k - i) + (l - j) * (l - j));
    }
    int main(){
        n = read(); m = read(); d = read(); s = 2008; t = 2009;
        for(int i = 1; i <= n; ++i)
           for(int j = 1; j <= m; ++j){
           	  ch = getchar();
           	  while(ch < '0' || ch > '9') ch = getchar();
           	  h[i][j] = ch - '0';
           }
        for(int i = 1; i <= n; ++i)
           for(int j = 1; j <= m; ++j){
           	  ch = getchar();
           	  while(ch != 'L' && ch != '.') ch = getchar();
           	  if(ch == 'L') Add(s, r(i, j), 1), ++tot;
           	  if(min(min(i, j), min(n - i + 1, m - j + 1)) <= d) Add(c(i, j), t, INF);
           	  Add(r(i, j), c(i, j), h[i][j]);
           }
        for(int i = 1; i <= n; ++i)
           for(int j = 1; j <= m; ++j)
              for(int k = 1; k <= n; ++k)
                 for(int l = 1; l <= m; ++l)
                    if(dis(i, j, k, l) <= d)
                      Add(c(i, j), r(k, l), INF), Add(c(k, l), r(i, j), INF);
        printf("%d
    ", tot - dinic());
        return 0;
    }
    
  • 相关阅读:
    Java笔记(06):如何使用JDK提供的帮助文档
    Java笔记(05):面向对象--继承
    MySql:基本SQL
    Oracle:简单SQL程序、存储过程、触发器
    Oracle:批量操作、视图、序列、简单SQL程序
    力扣(LeetCode)两整数之和 个人题解
    力扣(LeetCode)买卖股票的最佳时机 个人题解
    力扣(LeetCode)环形链表 个人题解
    力扣(LeetCode)找不同 个人题解
    力扣(LeetCode)从不订购的客户-数据库题 个人题解
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/10326623.html
Copyright © 2011-2022 走看看