1515 - Pool construction(最大流最小割模型)

53 篇文章 0 订阅
27 篇文章 0 订阅

该题是一道经典的最小割题目 。  最近学习图论以来一直不是很明白最小割是什么,通过该题,有了一定的认识 。

首先我们要知道最大流最小割定理 :对于任意一个只有一个源和一个汇的图来说,从源到汇的最大流等于最小割 。

也就是说,对于一个图中的两个集合AB,通过删除一些边让他们恰好不连通,那么删掉的这些边就叫做他们的割了 。  那么最小割和网络流有什么关系呢? 为什么最小割定理是对的呢? 其实很简单,刚才说了,我们要删除一些边让他们无法连通  。  对应到最大流中就是说残量网络中不存在增广路,那么此时的流就是最大流,自然也是最小割(因为我们还可以继续删边,不过无论怎么删都不会再存在增广路,但是这个割就大了)。 

理解了这一点之后,问题的关键就是如何建立模型,将割边所需的花费对应到最大流的流量上来 。

该题不同于普通的最小割,因为洞和草可以互相转化,那么我们先将问题简化,加入石头和草不能相互转化,那么怎么求最小割? 别跟我说暴力啊, 我们用网络流来求,那么我们可以将源点与草地连接,洞与汇点连接,且他们的容量都为无穷大就可以了,这样,使得网络不再连通之时洞和草就被完全割断了! 那么我们加上可以相互转化的条件后,显然要将费用和流量相对应,那么该题就迎仍而解了。 所以这也是为什么要将那些不可更改的草与源点的容量改成无穷大的原因了。

紫书上介绍的Edmonds-Karp算法确实比较慢,大概要跑0.666s的样子,套用训练指南上的Dinic算法,0.023s 。 大家暂时无需搞懂原理,接口类似套上就行,当然有兴趣的还是搞懂为好。

细节参见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1000000000;
const int maxn = 50*50 + 10;
int T,cnt,n,m,dd,ff,bb,t,k,vis[maxn],cur[maxn],d[maxn];
char s[maxn][maxn];
struct Edge {
  int from, to, cap, flow;
};
bool operator < (const Edge& a, const Edge& b) {
  return a.from < b.from || (a.from == b.from && a.to < b.to);
}
struct Dinic {
  int n, m, s, t;
  vector<Edge> edges;    // 边数的两倍
  vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
  bool vis[maxn];        // BFS使用
  int d[maxn];           // 从起点到i的距离
  int cur[maxn];         // 当前弧指针
void init(int n) {
    for(int i = 0; i < n; i++) G[i].clear();
    edges.clear();
}
void AddEdge(int from, int to, int cap) {
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    vis[s] = 1;
    d[s] = 0;
    while(!Q.empty()) {
      int x = Q.front(); Q.pop();
      for(int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if(!vis[e.to] && e.cap > e.flow) {
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
}
int DFS(int x, int a) {
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int& i = cur[x]; i < G[x].size(); i++) {
      Edge& e = edges[G[x][i]];
      if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i]^1].flow -= f;
        flow += f;
        a -= f;
        if(a == 0) break;
      }
    }
    return flow;
}
int Maxflow(int s, int t) {
    this->s = s; this->t = t;
    int flow = 0;
    while(BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }
};
Dinic g;
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d%d%d",&m,&n,&dd,&ff,&bb);
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
        int ans = 0; g.init(n*m+5);
        for(int i=1;i<=n;i++) {
            if(s[i][1] == '.') { s[i][1] = '#'; ans += ff; }
            if(s[i][m] == '.') { s[i][m] = '#'; ans += ff; }
        }
        for(int i=1;i<=m;i++) {
            if(s[1][i] == '.') { s[1][i] = '#'; ans += ff; }
            if(s[n][i] == '.') { s[n][i] = '#'; ans += ff; }
        }
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                if(s[i][j] == '#') {
                    int cap = INF;
                    if(i != 1 && i != n && j != 1 && j != m) cap = dd;
                    g.AddEdge(0,(i-1)*m+j,cap);
                }
                else g.AddEdge((i-1)*m+j,n*m+1,ff);
                if(i > 1) g.AddEdge((i-1)*m+j,(i-1-1)*m+j,bb);
                if(i < n) g.AddEdge((i-1)*m+j,(i)*m+j,bb);
                if(j > 1) g.AddEdge((i-1)*m+j,(i-1)*m+j-1,bb);
                if(j < m) g.AddEdge((i-1)*m+j,(i-1)*m+j+1,bb);
            }
        }
        ans += g.Maxflow(0,n*m+1);
        printf("%d\n",ans);
    }
    return 0;
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dmhsq-mysql-pool 是一个用于连接和管理 MySQL 数据库连接的资源池。在开发中,我们经常需要与数据库进行交互,执行查询、插入、更新等操作。然而,直接与数据库建立连接的方式会导致性能下降和资源浪费。 dmhsq-mysql-pool 提供了一种解决方案,它通过连接池的方式来管理数据库连接,减少了频繁创建和销毁连接的操作,提高了数据库操作的效率。连接池中维护了一定数量的数据库连接,当需要与数据库进行交互时,从连接池中获取一个空闲的连接,执行完操作后,将连接归还给连接池,而不是直接关闭。 使用 dmhsq-mysql-pool 的好处有以下几点: 1. 提高性能:通过使用连接池,避免了频繁创建和销毁连接的开销,减少了连接的等待时间,提高了数据库操作的性能。 2. 资源控制:连接池可以配置最大连接数量,防止连接线程过多导致数据库崩溃。同时可以配置最小连接数量,避免连接过少导致系统响应变慢。 3. 连接复用:连接池可以重复利用连接,避免了每次操作都重新创建连接的开销,提高了效率。 4. 连接管理:连接池可以对连接进行管理,包括超时时间、连接断开检测等,保证连接的可靠性和稳定性。 5. 简化代码:使用 dmhsq-mysql-pool 可以简化与数据库交互的代码,只需要从连接池获取连接和归还连接即可,不需要手动管理连接。 综上所述,dmhsq-mysql-pool 是一个非常有用的数据库连接管理工具,它可以提高数据库操作的性能和效率,同时简化了代码的编写。在开发中,合理使用连接池可以有效地提升系统的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值