Forethought Future Cup - Elimination Round G. Zoning Restrictions 最大流(最小割)

題目鏈接: https://codeforces.com/contest/1146/problem/G

題意:

你現在要給 nn 個位置制定高度 hi(1<=hi<=H)h_i (1<=h_i<=H) ,每個位置 ii 的高度可以帶來 hi2h_i^2 的收益,但是有 mm 條限制,每個限制 jj 的信息爲 lj,rj,xj,cjl_j,r_j,x_j,c_j 表示從位置 ljl_j 位置 rjr_j 當中如果有任意一個位置的高度超過了 xjx_j 那麼就要罰款 cjc_j ,現在問你最大的總收益爲多少。

做法:

因爲 n,H,mn,H,m 的大小均不超過 5050 ,所以還是很明顯能感受到是最大流的。套路無非就是 原最大收益-最小代價,代價在 只到達這個高度的損失 和 到達這個高度所要接受的罰款 裏面選出更小的,那麼這個更小的值的就靠 最大流=最小割 來維護了。

我想了挺久的,其實一開始方向蠻對的,每個位置每個高度一個點,每個條件一個點,但是不知道爲什麼後來就偏了,想用區間來表示(腦子瓦特了還順着這個錯誤的方向想了很久)。

略過略過,其實沿着一開始的思路的話還是很順的想的。把點按照高度拆開,高度 zz 向高度 z+1z+1 連一條只達到高度 z+1z+1 時要損失的代價。然後將限制條件 mjm_j中每一個合法的位置 pos(lj<=pos<=rj)pos(l_j<=pos<=r_j) 的高度爲 xj+1x_j+1 的點向限制條件連一條邊, mjm_j 本身向匯點連一條代價這麼多的邊即可。

畫了個醜陋的圖,第一個樣例幫助理解。
在這裏插入圖片描述

代碼

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
using namespace std;
const int maxn=2800;
const int maxm=30005;
const int inf = 1<<30;
typedef long long ll;
int nex[maxm],to[maxm],cap[maxm],from[maxm];
int n,m,h,cnt,head[maxn],d[maxn],sp,tp;//原點,匯點
//理論複雜度n2*m
void add(int u,int v,int c){
    //printf("from = %d to = %d  cap = %d\n",u,v,c);
    from[cnt]=u,to[cnt]=v,cap[cnt]=c,nex[cnt]=head[u],head[u]=cnt++;
    from[cnt]=v,to[cnt]=u,cap[cnt]=0,nex[cnt]=head[v],head[v]=cnt++;
}
int bfs(){
    queue <int> q;
    memset(d,-1,sizeof(d));
    d[sp]=0;
    q.push(sp);
    while(!q.empty()){
        int cur=q.front();
        q.pop();
        for(int i=head[cur];i!=-1;i=nex[i]){
            int u=to[i];
            if(d[u]==-1 && cap[i]>0){
                d[u]=d[cur]+1;
                q.push(u);
            }
        }
    }
    return d[tp] != -1;
}
int dfs(int a,int b){
    int r=0;
    if(a==tp)return b;
    for(int i=head[a];i!=-1 && r<b;i=nex[i])
    {
        int u=to[i];
        if(cap[i]>0 && d[u]==d[a]+1)
        {
            int x=min(cap[i],b-r);
            x=dfs(u,x);
            r+=x;
            cap[i]-=x;
            cap[i^1]+=x;
        }
    }
    if(!r)d[a]=-2;
    return r;
}

int dinic(int sp,int tp){
    int total=0,t;
    while(bfs()){
        while(t=dfs(sp,inf))
        total+=t;
    }
    return total;
}
int gain(int id,int hei){
    return (id-1)*(h+1)+hei+1;
}
int sub(int x){
    return h*h-x*x;
}
int main(){
    cnt=0;
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&h,&m);
    int ans=n*h*h,np=(h+1)*n;
    sp=0,tp=np+m+1;
    rep(i,1,n){
        add(sp,gain(i,0),inf);
        rep(j,1,h){
            add(gain(i,j-1),gain(i,j),sub(j-1));
        }
    }
    rep(i,1,m){
        int l,r,x,c; scanf("%d%d%d%d",&l,&r,&x,&c);
        if(x==h) continue;
        rep(j,l,r){
            add(gain(j,x+1),np+i,inf);
        }
        add(np+i,tp,c);
    }
    printf("%d\n",ans-dinic(sp,tp));
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章