QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#510153 | #4775. Pool construction | xixu | AC ✓ | 10ms | 11944kb | C++17 | 4.6kb | 2024-08-08 21:34:22 | 2024-08-08 21:34:23 |
Judging History
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