• UVa 1515


    链接:

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4261

    题意:

    输入一个h行w列的字符矩阵,草地用“#”表示,洞用“.”表示。
    你可以把草改成洞,每格花费为d,也可以把洞填上草,每格花费为f。
    最后还需要在草和洞之间修围栏,每条边的花费为b。
    整个矩阵第一行/列和最后一行/列必须都是草。
    求最小花费。2≤w,h≤50,1≤d, f, b≤10000。

    分析:

    围栏的作用是把草和洞隔开,让人联想到了“割”这个概念。
    可是“割”只是把图中的结点分成了两个部分,而本题中,草和洞都能有多个连通块。怎么办呢?
    添加源点S和汇点T,与其他点相连,则所有本不连通的草地/洞就能通过源点和汇点间接连起来了。
    由于草和洞可以相互转换,而且转换还需要费用,所以需要一并在“割”中体现出来。
    为此,规定与S连通的都是草,与T连通的都是洞,
    则S需要往所有草格子连一条容量为d的边,表示必须把这条弧切断(割的容量增加d),
    这个格子才能“叛逃”到T的“阵营”,成为洞。
    由于题目说明了最外圈的草不能改成洞,从S到这些草格子的边容量应为正无穷
    (在这之前需要把边界上的所有洞填成草,累加出这一步所需的费用)。
    同理,所有不在边界上的洞格子往T连一条弧,费用为f,
    表示必须把这条弧切断(割的容量增加f),才能让这个洞变成草。
    相邻两个格子u和v之间需要连两条边u->v和v->u,容量均为b,
    表示如果u是草,v是洞,则需要切断弧u->v;如果v是草,u是洞,则需要切断弧v->u。
    这样,用最大流算法求出最小割,就可以得到本题的最小花费。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 #include <vector>
      5 using namespace std;
      6 
      7 /// 结点下标从0开始,注意maxn
      8 struct Dinic {
      9     static const int maxn = 50 * 50 + 5;
     10     static const int INF = 0x3f3f3f3f;
     11     struct Edge {
     12         int from, to, cap, flow;
     13     };
     14 
     15     int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号
     16     vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧
     17     vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
     18     bool vis[maxn]; // BFS使用
     19     int d[maxn]; // 从起点到i的距离
     20     int cur[maxn]; // 当前弧下标
     21 
     22     void init(int n) {
     23         this->n = n;
     24         edges.clear();
     25         for(int i = 0; i < n; i++) G[i].clear();
     26     }
     27     void AddEdge(int from, int to, int cap) {
     28         edges.push_back((Edge){from, to, cap, 0});
     29         edges.push_back((Edge){to, from, 0, 0});
     30         m = edges.size();
     31         G[from].push_back(m-2);
     32         G[to].push_back(m-1);
     33     }
     34     bool BFS() {
     35         memset(vis, 0, sizeof(vis));
     36         queue<int> Q;
     37         Q.push(s);
     38         vis[s] = 1;
     39         d[s] = 0;
     40         while(!Q.empty()) {
     41             int x = Q.front();  Q.pop();
     42             for(int i = 0; i < G[x].size(); i++) {
     43                 Edge& e = edges[G[x][i]];
     44                 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧
     45                     vis[e.to] = 1;
     46                     d[e.to] = d[x] + 1;
     47                     Q.push(e.to);
     48                 }
     49             }
     50         }
     51         return vis[t];
     52     }
     53     int DFS(int x, int a) {
     54         if(x == t || a == 0) return a;
     55         int flow = 0, f;
     56         for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧
     57             Edge& e = edges[G[x][i]];
     58             if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) {
     59                 e.flow += f;
     60                 edges[G[x][i]^1].flow -= f;
     61                 flow += f;
     62                 a -= f;
     63                 if(a == 0) break;
     64             }
     65         }
     66         return flow;
     67     }
     68     int Maxflow(int s, int t) {
     69         this->s = s;  this->t = t;
     70         int flow = 0;
     71         while(BFS()) {
     72             memset(cur, 0, sizeof(cur));
     73             flow += DFS(s, INF);
     74         }
     75         return flow;
     76     }
     77     vector<int> Mincut() { // 在Maxflow之后调用
     78         vector<int> ans;
     79         for(int i = 0; i < edges.size(); i++) {
     80             Edge& e = edges[i];
     81             if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i);
     82         }
     83         return ans;
     84     }
     85 } dc;
     86 
     87 const int INF = 0x3f3f3f3f;
     88 const int UP = 50 + 5;
     89 int r, c;
     90 char site[UP][UP];
     91 inline int id(int rr, int cc) { return rr*c+cc; }
     92 
     93 int main() {
     94     int T, d, f, b;
     95     scanf("%d", &T);
     96     while(T--) {
     97         scanf("%d%d%d%d%d", &c, &r, &d, &f, &b);
     98         for(int i = 0; i < r; i++) scanf("%s", site[i]);
     99         int ans = 0;
    100         for(int i = 0; i < r; i++) {
    101             if(site[i][0] == '.') site[i][0] = '#', ans += f;
    102             if(site[i][c-1] == '.') site[i][c-1] = '#', ans += f;
    103         }
    104         for(int i = 0; i < c; i++) {
    105             if(site[0][i] == '.') site[0][i] = '#', ans += f;
    106             if(site[r-1][i] == '.') site[r-1][i] = '#', ans += f;
    107         }
    108 
    109         dc.init(r*c+2);
    110         int start = r*c, finish = r*c+1;
    111         for(int rr = 0; rr < r; rr++) {
    112             for(int cc = 0; cc < c; cc++) {
    113                 if(site[rr][cc] == '#') {
    114                     int cap = (rr==0 || rr==r-1 || cc==0 || cc==c-1) ? INF : d;
    115                     dc.AddEdge(start, id(rr,cc), cap);
    116                 } else dc.AddEdge(id(rr,cc), finish, f);
    117                 if(rr > 0) dc.AddEdge(id(rr,cc), id(rr-1,cc), b);
    118                 if(rr < r-1) dc.AddEdge(id(rr,cc), id(rr+1,cc), b);
    119                 if(cc > 0) dc.AddEdge(id(rr,cc), id(rr,cc-1), b);
    120                 if(cc < c-1) dc.AddEdge(id(rr,cc), id(rr,cc+1), b);
    121             }
    122         }
    123         printf("%d
    ", ans + dc.Maxflow(start, finish));
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    大数据-KNN算法
    Java-单链表的实现
    Python分析《武林外传》
    Java-javaFx库运用-自动弹跳的球
    Java-javaFx库运用-时钟显示
    Python爬虫-《神雕侠侣》
    大数据-决策树
    Java--用键盘控制小球
    Java--下大雪模拟
    Java File ——Io流复习
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9548236.html
Copyright © 2020-2023  润新知