hdu6611----費用流

K Subsequence

題意:給定一個長度爲\(n\)的數字序列,現能夠從中選取k個單調上升的子序列,且每一個元素至多隻能被選中一次,問k個子序列元素和的最大值。php

題解:對數列每一項拆點,鏈接流量爲1,費用爲\(-a[i]\)的邊,全部項的右端點與其後大於等於這一項的項的左端點連流量1,費用0的邊。源點與匯點再分別與各項左右端點連邊。超級源點與源點連流量k費用0的邊。跑最小費用最大流。node

#include <bits/stdc++.h>
using namespace std;
int n,k,a[2005];
typedef pair<int,int> pa;
struct node{
    int to,flo,cost,rev;
};
int ss,s,t,tt;
vector<node> gra[5000];
void add(int u,int v,int flo,int cost){
    node tmp;
    tmp.to=v; tmp.flo=flo; tmp.cost=cost; tmp.rev=gra[v].size();
    gra[u].push_back(tmp);
    tmp.to=u; tmp.flo=0; tmp.cost=-cost; tmp.rev=gra[u].size()-1;
    gra[v].push_back(tmp);
}
int h[5000],dis[5000];
int pre[5000],ppre[5000];
bool dij(){
    for(int i=ss;i<=tt;i++) dis[i]=0x3f3f3f3f;
    priority_queue<pa,vector<pa>,greater<pa> > que;
    que.push(make_pair(0,ss));
    dis[ss]=0;
    while(!que.empty()){
        pa now=que.top(); que.pop();
        if(dis[now.second]<now.first) continue;
        int u=now.second;
        int siz=gra[u].size();
        for(int i=0;i<siz;i++){
            node ttt=gra[u][i];
            int tmp=ttt.cost+h[u]-h[ttt.to];
            if(ttt.flo>0&&dis[ttt.to]>dis[u]+tmp){
                dis[ttt.to]=dis[u]+tmp;
                pre[ttt.to]=u;
                ppre[ttt.to]=i;
                que.push(make_pair(dis[ttt.to],ttt.to));
            }
        }
    }
    return dis[tt]!=0x3f3f3f3f;
}
int solve(){
    int ans=0;
    while(dij()){
        for(int i=ss;i<=tt;i++) h[i]+=dis[i];
        ans -= h[tt];
        int now=tt;
        while(now!=ss){
            int nxt=pre[now],id=ppre[now];
            gra[nxt][id].flo--;
            gra[gra[nxt][id].to][gra[nxt][id].rev].flo++;
            now=nxt;
        }
    }
    return ans;
} 
int main(){
    int T;
    cin >> T;
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]); 
        ss=0; s=1; t=n*2+2; tt=n*2+3;
        for(int i=ss;i<=tt;i++) gra[i].clear();
        add(0,1,k,0);
        add(t,tt,k,0);
        for(int i=1;i<=n;i++){
            int u=i*2,v=i*2+1;
            add(1,u,1,0);
            add(u,v,1,-a[i]); 
            add(v,t,1,0);
            for(int j=i+1;j<=n;j++){
                if(a[j]>=a[i]){
                    add(v,j*2,1,0);
                }
            }
        }
        cout << solve() << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索