AcWing 382. K取方格數
阿新 • 來源:網路 • 發佈:2022-12-10
思路:
這裡我們可以設一個源點S1和一個超級源點S,一個匯點T,每個點先拆點(容量為1,費用為aij)、向下和右建邊(容量為1、費用為0)、S1向每個點建邊(容量為1、費用為0)、每個點向T建邊(容量為1、費用為0);最後,S向S1建邊(容量為k、費用為0),這種建圖方式也是本題的答案
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define douinf 0x3f3f3f3f
#define IO ios::sync_with_stdio(false)
#define bug cout << "-----\n"
#define eps 1e-10
#define endl '\n'
typedef long long ll;
const int N = 20000;
const int M = 100000;
int e[M],ne[M],w[M],f[M],h[N],idx;
int S,S1,T,n,pre[N],info[N],dis[N],vis[N],a[N][N];
queue<int> q;
void add(int x,int y,int z1,int z2) {
e[idx] = y;w[idx] = z1;f[idx] = -z2;ne[idx] = h[x];h[x] = idx ++;
e[idx] = x;w[idx] = 0;f[idx] = z2;ne[idx] = h[y];h[y] = idx ++;
}
int get(int x,int y) {
return (x - 1) * n + y;
}
int spfa() {
memset(dis , 0x3f , sizeof dis);
memset(vis , 0 , sizeof vis);
memset(info , 0 , sizeof info);
while(!q.empty())q.pop();
info[S] = inf;q.push(S);dis[S] = 0;
while(!q.empty()) {
//cout << q.size() << endl;
//bug;
int g = q.front();q.pop();
vis[g] = 0;
for(int i = h[g] ; ~i ; i = ne[i]) {
//cout << i << endl;
int x = e[i];
if(dis[x] > dis[g] + f[i] && w[i]) {
dis[x] = dis[g] + f[i];
pre[x] = i;
info[x] = min(info[g] , w[i]);
if(!vis[x]) {
vis[x] = 1;
q.push(x);
}
}
}
}
return info[T] > 0;
}
int EK() {
int res = 0;
while(spfa()) {
//bug;
int t = info[T];
res += t * dis[T];
for(int i = T ; i != S ; i = e[pre[i] ^ 1]) {
w[pre[i]] -= t;
w[pre[i] ^ 1] += t;
}
}
return res;
}
int main() {
memset(h , -1 , sizeof h);
int k;cin >> n >> k;
S = 0;S1 = N - 3;T = N - 2;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
cin >> a[i][j];
int len = n * n;
for(int i = 1 ; i <= n ; i ++) {
for(int j = 1 ; j <= n ; j ++) {
add(get(i , j) + len , T , 1 , 0);
add(S1 , get(i , j) , 1 , 0);
add(get(i , j) , get(i , j) + len , 1 , a[i][j]);
if(i + 1 <= n)add(get(i , j) + len , get(i + 1 , j) , 1 , 0);
if(j + 1 <= n)add(get(i , j) + len , get(i , j + 1) , 1 , 0);
}
}
add(S , S1 , k , 0);
cout << -EK() << endl;
return 0;
}
