Codeforces CodeCraft-20 (Div. 2) E贪心,费用流


Codeforces CodeCraft-20 (Div. 2) E,费用流
原题

题意:

现有n个人需要成为队员或者观众,一个team有p(<7)个位置,需要k个观众。
每个人 当观众贡献ai ,当不同位置的队员分别贡献pij
问如何安排贡献最大。

思路:

这个题官方题解状态压缩DP,这里考虑一个网络流做法。
不考虑要选k个观众,显然就是一个简单的dp。
因为还要选k个观众,需要要分析这个问题的性质。这里我们想一个贪心的思路,对队员按ai进行排序。
先不考虑队员,则我们先选取topk的观众,加进来队员的选择,发现可以分为两种情况讨论:
1 选取的队员在前k个收,我们则需要在(k,n]中再选择一个当观众,考虑只有p个队队员,实际上只需要在(k,k+p]中选一个代替他来当观众。

2 选取的队员在后k个,则直接选择就好。但实际上只需要在topP中做出选择,只有一个p的时候就是最大的那个,多个p的时候涉及的选择,但是一定在topP之中。

根据上述结论,我们可以建图通过费用流帮我们选择(当然dp也可以)。需要准备的节点主要包括P[i],tmp,O(p)个点,O(p^2)条边。具体建图见代码。

代码:

#include 
using namespace std;
#define X first
#define Y second
#define PB push_back
#define LL long long
#define pii pair
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<q;
    for(int i = 0; i < N; i++){
        dis[i] = INF;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow &&dis[v] > dis[u] + edge[i].cost ){
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v]){
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    //return dis[t]<=0;
    if(pre[t] == -1)return false;
    else return true;
}

int minCostMaxflow(int s,int t,LL &cost){
    int flow = 0;
    cost = 0;
    while(spfa(s,t)){
        LL Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){
            if(Min > edge[i].cap - edge[i].flow)
                Min = edge[i].cap - edge[i].flow;
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i].cost * Min;
        }
        flow += Min;
    }
    return flow;
}

pair> a[maxn];
int main(){
    FIO;
    int n,p,k,x;
    cin>>n>>p>>k;
    set e;
    int cnt = n;
    int P[10];
    for(int i=0;i>a[i].X;
    for(int i=0;i>x,a[i].Y.PB(x);
    sort(a,a+n,greater>>());
    for(int i=0;i v;
        for(int j=0;j