Cost Flow simulation & revocable greedy

1. CF730I Olympiad in Programming and Sports

Effect: $ n $ personal, individual programming of the $ i $ capacity $ a_i $, athleticism $ b_i $, $ p $ to select a team composed of programming, $ s $ composed of two sports teams, each team benefits to players capacity and, seeking maximum benefit.

Cost flow approach is very clear that the opening two points $ X, Y $ express programming and sports, the sources even side to everyone, the price is $ 0 $ per person to $ X $ even side, the cost of programming ability, everyone to $ Y $ edge even a consideration of athletic ability, $ X $ to the edge of the sink and even a capacity of $ p $, $ Y $ to sink even point edge with a capacity of $ s $, then find the maximum cost maximum flow is the answer .

Consider the cost of the heap simulation flow. Every time augmented only four cases.

  • Adding people to a non-selected programming team
  • Adding a non-selected people to sports teams
  • Let a person from sports teams to the programming team, and then choose a non-selected people to sports teams
  • Let a person from the programming team to sports teams, and then select a person to unselected programming team

The first two cases can be directly heap maintain maximum. The latter two cases, then, when every decision, regarded the replacement of income can be thrown into a pile.

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head



const int N = 1e6+10;
int n, x, y;
int a[N], b[N], va[N], vb[N];
pii s[5];
priority_queue<pii> q[5];
ll ans;

pii get(priority_queue<pii> &q, int *v1, int *v2) {
    while (q.size()&&(v1[q.top().y]||v2[q.top().y])) q.pop();
    return q.empty()?pii(-INF,0):q.top();
}
void add(int u, int tp) {
    if (va[u]) ans-=a[u],va[u]=0,++x;
    if (vb[u]) ans-=b[u],vb[u]=0,++y;
    if (tp==1) ans+=a[u],va[u]=1,--x,q[4].push(pii(b[u]-a[u],u));
    else ans+=b[u],vb[u]=1,--y,q[3].push(pii(a[u]-b[u],u));
}

int main() {
    scanf("%d%d%d", &n, &x, &y);
    REP(i,1,n) scanf("%d",a+i);
    REP(i,1,n) scanf("%d",b+i);
    REP(i,1,n) { 
        q[1].push(pii(a[i],i));
        q[2].push(pii(b[i],i));
    }
    int tot = x+y;
    REP(i,1,tot) {
        s[1] = get(q[1],va,vb);
        s[2] = get(q[2],va,vb);
        s[3] = get(q[3],va,va);
        s[4] = get(q[4],vb,vb);
        s[3].x += s[2].x;
        s[4].x += s[1].x;
        if (!x) s[1].x=s[3].x=-INF;
        if (!y) s[2].x=s[4].x=-INF;
        int p = max_element(s+1,s+5)-s;
        if (p==1) add(s[1].y,1);
        else if (p==2) add(s[2].y,2);
        else if (p==3) add(s[3].y,1),add(s[2].y,2);
        else add(s[4].y,2),add(s[1].y,1);
    }
    printf("%lld\n", ans);
    REP(i,1,n) if (va[i]) printf("%d ",i);hr;
    REP(i,1,n) if (vb[i]) printf("%d ",i);hr;
}
View Code

 

2. NOI2019 sequence

Effect: Given two sequences $ a, b $, requires that each sequence is selected $ K $ elements, and the same position of the element to be selected from at least one $ $ L, and seeking the maximum selected elements.

First, you can get an obvious cost flow approach.

$ A $ source to each of the elements connected side, the cost of $ a_i $, $ b $ each element is connected to the sink side, the price of $ b_i $.

$ A $ for each edge point to the corresponding position of the point $ b $ connected.

Two points to open $ X, Y $, $ X $ $ connected to the capacity of the Y $ $ $ edge KL, KL represents $ $ select a different location.

$ A $ for each point and then connected to the $ X $, $ Y $ $ b $ connected to each point.

Finally, find a source to sink capacity is the maximum cost of $ K $ is the flow of the answer.

Consider cost flow simulation heap, sub-four cases.

  • Maximum selected from $ A $, $ b $ is also selected from the maximum (X to Y in claim still remaining flow)
  • $ A $, $ b $ selected the same location
  • Sorted previously selected maximum $ A $, $ b $ $ A $ corresponding to the selected location
  • $ B $ selected maximum, $ a $ had previously selected in the selected position corresponding to $ b $ 
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head



#ifdef ONLINE_JUDGE
const int N = 1e6+10;
#else
const int N = 567;
#endif

int n, k, l, a[N], b[N];
int va[N], vb[N];
priority_queue<pii> q[10];
struct t3 {int x,a,b;} f[10];
ll ans;
pii s[10];
int cost(int x, int y) {
    int ret = 0;
    if (x!=y) {
        if (vb[x]) ++ret; else --ret;
        if (va[y]) ++ret; else --ret;
    }
    return ret<0?-1:ret>0?1:0;
}
void add(int x, int y) {
    l += cost(x,y);
    ans += a[x]+b[y];
    va[x] = vb[y] = 1;
    if (!vb[x]) q[4].push(pii(b[x],x));
    if (!va[y]) q[3].push(pii(a[y],y));
}
pii get(priority_queue<pii> &q, int *v1, int *v2) {
    while (q.size()&&(v1[q.top().y]||v2[q.top().y])) q.pop();
    return q.empty()?pii(-INF,0):q.top();
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        REP(i,0,4) while (q[i].size()) q[i].pop();
        scanf("%d%d%d", &n, &k, &l);
        REP(i,1,n) scanf("%d",a+i);
        REP(i,1,n) scanf("%d",b+i);
        REP(i,1,n) {
            va[i] = vb[i] = 0;
            q[0].push(pii(a[i]+b[i],i));
            q[1].push(pii(a[i],i));
            q[2].push(pii(b[i],i));
        }
        l = k-l, ans = 0;
        REP(i,1,k) {
            s[0] = get(q[0],va,vb);
            s[1] = get(q[1],va,va);
            s[2] = get(q[2],vb,vb);
            s[3] = get(q[3],va,va);
            s[4] = get(q[4],vb,vb);
            f[0] = {s[1].x+s[2].x,s[1].y,s[2].y};
            f[1] = {s[0].x,s[0].y,s[0].y};
            f[2] = {s[1].x+s[4].x,s[1].y,s[4].y};
            f[3] = {s[2].x+s[3].x,s[3].y,s[2].y};
            if (l+cost(f[0].a,f[0].b)<0) f[0].x=-INF;
            int p = max_element(f,f+4,[](t3 a, t3 b){return a.x<b.x;})-f;
            add(f[p].a,f[p].b);
        }
        printf("%lld\n", ans);
    }
}
View Code

 

3. CF802O April Fools' Problem (hard)

The effect that: $ the n-$ questions, the first $ i $ days can cost $ A_ i $ prepared a question, spending $ b_ i $ print a question, prepare up to one, print up a preparation for the title can be left to print after day, seeking a minimum cost and makes ready to print $ k $ questions.

The interesting question is good, difficult to simulate the direct use of the heap, it seems that you can use to simulate the tree line. A very good practice is to write with the right half.

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head



const int N = 1e6+50;
int n, k, a[N], b[N];
priority_queue<int,vector<int>,greater<int> > q[2];

int main() {
    scanf("%d%d", &n, &k);
    REP(i,1,n) scanf("%d", a+i);
    REP(i,1,n) scanf("%d", b+i);
    int l = 0, r = 1.4e9;
    ll ans = 0;
    while (l<=r) {
        REP(i,0,1) while (q[i].size()) q[i].pop();
        ll ret = 0;
        int cnt = 0, mid = (ll)l+r>>1;
        REP(i,1,n) {
            q[0].push(a[i]);
            ll t1 = q[0].top()+(ll)b[i]-mid;
            ll t2 = q[1].empty()?INF:b[i]+q[1].top();
            if (t1<=0&&t1<=t2) {
                ret += t1, ++cnt;
                q[1].push(-b[i]);
                q[0].pop();
            }
            else if (t2<0) {
                ret += t2;
                q[1].pop();
                q[1].push(-b[i]);
            }
        }
        if (cnt>=k) ans=ret+(ll)k*mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld\n", ans);
}
View Code

 

4. hdu 6698 Coins

Effect: $ n $ group coins of $ I $ $ a_i a group element and $ $ $ B_i element, each selected or not, or selected from a_i $ $, or select all, for $ k \ le 2n $ obtained $ k $ to get the maximum number of coins of money.

This simulation can stack four options:

  • Take a maximum of $ a $
  • Added something a maximum of $ b $
  • Delete a $ a $, takes a maximum of $ a + b $
  • Delete a $ b $, takes a maximum of $ a + b $
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head



const int N = 1e6+10;
int n, a[N], b[N];
int va[N], vb[N];
priority_queue<pii> q[3];
priority_queue<pii,vector<pii>,greater<pii> > qq[2]; 
pii s[4];
void add(int u, int tp) {
    if (tp==0) va[u]=1,q[1].push(pii(b[u],u)),qq[0].push(pii(a[u],u));
    else vb[u]=1,qq[1].push(pii(b[u],u));
}
void work() {
    scanf("%d", &n);
    REP(i,0,2) while (q[i].size()) q[i].pop();
    REP(i,0,1) while (qq[i].size()) qq[i].pop();
    REP(i,1,n) {
        scanf("%d%d",a+i,b+i);
        q[0].push(pii(a[i],i));
        q[2].push(pii(a[i]+b[i],i));
        va[i] = vb[i] = 0;
    }
    ll ans = 0;
    REP(i,1,2*n) {
        while (q[0].size()&&va[q[0].top().y]) q[0].pop();
        s[0] = q[0].empty()?pii(-INF,0):q[0].top();
        while (q[1].size()&&(!va[q[1].top().y]||vb[q[1].top().y])) q[1].pop();
        s[1] = q[1].empty()?pii(-INF,0):q[1].top();
        while (q[2].size()&&va[q[2].top().y]) q[2].pop();
        s[2] = s[3] = q[2].empty()?pii(-INF,0):q[2].top();
        if (i==1) s[2].x = s[3].x = -INF;
        else { 
            while (qq[0].size()&&(!va[qq[0].top().y]||vb[qq[0].top().y])) qq[0].pop();
            if (qq[0].size()) s[2].x -= qq[0].top().x;
            else s[2].x = -INF;
            while (qq[1].size()&&!vb[qq[1].top().y]) qq[1].pop();
            if (qq[1].size()) s[3].x -= qq[1].top().x;
            else s[3].x = -INF;
        }
        int p = max_element(s,s+4)-s;
        ans += s[p].x;
        if (p<=1) add(s[p].y,p);
        else { 
            //要注意先删除在添加, 不然qq会变
            if (p==2) va[qq[0].top().y]=0,q[0].push(qq[0].top());
            else vb[qq[1].top().y]=0,q[1].push(qq[1].top());
            add(s[p].y,0),add(s[p].y,1);
        }
        printf("%lld%c",ans," \n"[i==2*n]);
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) work();
}
View Code

Guess you like

Origin www.cnblogs.com/uid001/p/11348566.html
Recommended