QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#510153#4775. Pool constructionxixuAC ✓10ms11944kbC++174.6kb2024-08-08 21:34:222024-08-08 21:34:23

Judging History

你现在查看的是最新测评结果

  • [2024-08-08 21:34:23]
  • 评测
  • 测评结果:AC
  • 用时:10ms
  • 内存:11944kb
  • [2024-08-08 21:34:22]
  • 提交

answer

#include<bits/stdc++.h>
using namespace std;
// #define int short
#define int long long
#define num(i , j) (i - 1) * m + j
typedef long long ll;
typedef pair<int , int> PII;


const int M = 2e5 + 10 , inf = 0x3f3f3f3f3f3f3f3f , N = 2e4 + 10;
int n , m , s , t;

int h[N] , e[M] , ne[M] , w[M] , idx;
int cur[N];
int dep[N];
char c[N][N];
PII dd[4] = {{-1 , 0} , {1 , 0} , {0 , 1} , {0 , -1}};



void add(int a , int b , int c)
{
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx ++;
}


bool bfs()
{
    for(int i = 1; i <= n * m + 5; i ++) dep[i] = -1; // 初始化层数标记数组

    queue<int> q;
    q.push(s);
    dep[s] = 0;
    cur[s] = h[s];

    while(q.size())
    {
        int u = q.front();
        q.pop();
        for(int i = h[u]; i != -1; i = ne[i])
        {
            int v = e[i];
            if(dep[v] == -1 && w[i]) //若 v点 还未访问过,且 u -> v 的边余量为正
            {
                dep[v] = dep[u] + 1;
                cur[v] = h[v]; // 复制 1 份 h 给 cur
                
                if(v == t) // 若 bfs 到终点了,说明能找到增广路
                    return 1; 
                q.push(v);
            }
        }
    }
    return 0;
}


int dfs(int u , int limit) // limit -> 流入u点的流量
{
    if(u == t) // 若 dfs 到了汇点t,说明找到了一条增广路径
        return limit; // 返回增加的流量limit

    int flow = 0; // flow -> u点 分给 其他点 的 总流量
    for(int i = cur[u]; i != -1; i = ne[i]) // 循环u的所有出边,注意这里用的是cur数组,就是当前弧优化,访问所有还可以扩大流量的出边
    {
        int v = e[i];
        cur[u] = i; //更新cur,循环到i说明u点已经用到了第i条边,也说明前i-1条边已经被榨干了(所以才用到了第i条边),因此下次直接从u点用第i条边就可以了,所以cur[u]更新为i就可以了

        if(dep[v] == dep[u] + 1 && w[i]) // 若 v 是 u 的下一层,且 u -> v 的残量为正,走 u -> v 这条路
        {
            int temp = min(limit - flow , w[i]); // temp 是 u 能给 v 分到的最大流量
            int minf = dfs(v , temp); // minf 是递归返回的流量,就是这条增广路上最大能加的流量大小

            // 更新残留网络
            w[i] -= minf; // 正向边 -> 余量
            w[i ^ 1] += minf; // 反向边 -> 流量

            flow += minf; // 分出去的流量 + minf

            if(flow == limit) // 若 分出去的 flow == 流入的 limit 时,就不用继续往下dfs了
                return flow;
        }
    }
    return flow;    
}


ll dinic()
{
    ll ans = 0;
    while(bfs()) // 当能bfs分层时 == 能找到增广路
    {
        ans += dfs(s , inf); // ans + dfs能增加的流量 ,ans不断增加,直到没有增广路了,ans就是最大流了
    }

    return ans;
}


void solve()
{
    cin >> m >> n;

    for(int i = 1; i <= n * m + 5; i ++) h[i] = -1;
    idx = 0;
    int d , f , b;
    cin >> d >> f >> b;
    int ans = 0;

    s = n * m + 1 , t = n * m + 2;
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= m; j ++)
        {
            cin >> c[i][j];
            if(i == 1 || i == n || j == 1 || j == m)
            {
                if(c[i][j] == '.')
                {
                    ans += f;
                }
                add(s , num(i , j) , inf);
                add(num(i , j) , s , 0);
            }
            else
            {
                if(c[i][j] == '.')
                {
                    add(num(i , j) , t , f);
                    add(t , num(i , j) , 0);
                }
                else
                {
                    add(s , num(i , j) , d);
                    add(num(i , j) , s , 0);
                }
            }
        }
    }
    // cout << ans << '\n';

    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= m; j ++)
        {
            for(int k = 0; k < 4; k ++)
            {
                int x = i + dd[k].first , y = j + dd[k].second;
                if(x > n || y > m || x < 1 || y < 1) continue ;
                add(num(i , j) , num(x , y) , b);
                add(num(x , y) , num(i , j) , 0);
            }
        }
    }



    


    // cout << ans << '\n';
    cout << dinic() + ans << '\n';


}



signed main()
{
    cin.tie(0);cout.tie(0);
    ios::sync_with_stdio(false);

    int _ = 1;
    cin >> _;
    while(_ --)
    {
        solve();
    }

    return 0;
}

詳細信息

Test #1:

score: 100
Accepted
time: 1ms
memory: 9944kb

input:

3
3 3
5 5 1
#.#
#.#
###
5 4
1 8 1
#..##
##.##
#.#.#
#####
2 2
27 11 11
#.
.#

output:

9
27
22

result:

ok 3 lines

Test #2:

score: 0
Accepted
time: 10ms
memory: 11944kb

input:

56
3 3
5 5 1
#.#
#.#
###
5 4
1 8 1
#..##
##.##
#.#.#
#####
2 2
1 1 1
##
##
2 2
1 10000 1
..
..
5 4
20 41 9
#####
##.##
#.#.#
#####
5 4
20 41 10
#####
##.##
#.#.#
#####
5 4
20 41 11
#####
##.##
#.#.#
#####
5 4
20 39 10
#####
##.##
#.#.#
#####
3 3
9760 9015 711
.#.
#.#
###
5 5
7415 7931 2080
.....
#.....

output:

9
27
0
40000
108
120
123
117
20874
100110
112364
203900
271440
462119
490330
1746528
1067774
1055196
2609818
2094932
5199902
13978
73960
99018
262976
224632
78984
167795
392774
649054
1232290
135876
318982
413042
1479538
1680354
349557
540100
2101110
335884
2245998
170698
780013
1804351
2998519
3661...

result:

ok 56 lines