1. 程式人生 >實用技巧 >其它 >AcWing 382. K取方格數

AcWing 382. K取方格數


思路:
這裡我們可以設一個源點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;
}