19 hdu多校 K Subsequence //最小费用流

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41730604/article/details/97687871

http://acm.hdu.edu.cn/showproblem.php?pid=6611

题意:

给n个数,找出k个不重复使用同一个元素的上升的子序列,使得选的元素的和最大。

题解:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int LG = 50;
const int MX = 2e5+10;
const int max_n=4005;
struct no{int to,cap,cost,rev;};
struct qno{int v,d;}; //队列节点
bool operator<(const qno &x,const qno &y) {return x.d>y.d;} //队列cmp重写

vector<no>g[max_n];
int dis[max_n],h[max_n]; //最短距离,顶点的势
int prevv[max_n],preve[max_n]; //在vector下记录路径

void addedge(int from,int to,int cap,int cost){
    g[from].push_back((no){to,cap,cost,g[to].size()});
    g[to].push_back((no){from,0,-cost,g[from].size()-1});
}
int min_cost_flow(int s,int t,int f,int n){//注意n变化了!!!!!!!!!!!!!!!!!
    int res=0; //answer
    for(int i=0;i<=n;i++) h[i]=0; //初始化h
    while(f>0){
        priority_queue<qno>q;
        for(int i=0;i<=n;i++) dis[i]=INT_MAX/2;
        dis[s]=0;
        q.push((qno){s,0});
        while(!q.empty()){
            qno now=q.top();q.pop();
            int v=now.v;
            if(dis[v]<now.d) continue;
            for(int i=0;i<(int)g[v].size();i++){
                no &e=g[v][i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){ //加入啦势
                    dis[e.to]=dis[v]+e.cost+h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    q.push((qno){e.to,dis[e.to]});
                }
            }
        }
        if(dis[t]==INT_MAX/2) return -1;
        for(int v=0;v<=n;v++) h[v]+=dis[v];
        int d=f; //找增广路
        for(int v=t;v!=s;v=prevv[v]) d=min(d,g[prevv[v]][preve[v]].cap);
        f-=d;res+=d*h[t];
        for(int v=t;v!=s;v=prevv[v]){
            no &e=g[prevv[v]][preve[v]];
            e.cap-=d;
            g[v][e.rev].cap+=d;
        }
    }
    return res;
}
int a[MX];
int main(){
    int T;cin>>T;while(T--){
        int n,k;cin>>n>>k;
        for(int i=0;i<=n*2+3;i++)g[i].clear();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) addedge(i*2,i*2+1,1,-a[i]);
        for(int i=1;i<=n;i++) addedge(1,i*2,1,0),addedge(i*2+1,n*2+2,1,0);
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++) {
                if(a[j]>=a[i]) addedge(i*2+1,j*2,1,0);
            }
        }
        addedge(0,1,k,0);
        cout<<-min_cost_flow(0,n*2+2,k,2*n+2)<<endl;
    }
    return 0;
}

 

展开阅读全文

没有更多推荐了,返回首页