有流量上界最小费用最大流

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const ll inf=0x3f3f3f3f;
const int N=1e4+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
struct edge {
	int to, cap, cost, rev;
};
int V,H[N+5],dis[N+5],PreV[N+5],PreE[N+5];
vector<edge> G[N+5];
void init(int n) {
	V=n;
	for(int i=0; i<=V; ++i) G[i].clear();
}
void AddEdge(int from,int to,int cap,int cost) {
	G[from].push_back(edge {to,cap,cost,SZ(G[to])});
	G[to].push_back(edge {from,0,-cost,SZ(G[from])-1});
}
int Min_cost_max_flow(int s,int t,int f,int& flow) {
	//源点   汇点  限定流量   最后的最大流
	int res = 0;
	fill(H,H+1+V,0);
	while (f) {
		priority_queue <pair<int, int>,vector<pair<int,int>>,greater<pair<int,int>> > q;
		fill(dis,dis+1+V,inf);
		dis[s]=0;
		q.push(pair<int, int>(0,s));
		while(!q.empty()) {
			pair<int,int>now=q.top();
			q.pop();
			int v=now.second;
			if(dis[v]<now.first) continue;
			for (int i=0; i<SZ(G[v]); ++i) {
				edge& 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];
					PreV[e.to]=v,PreE[e.to]=i;
					q.push(pair<int,int>(dis[e.to],e.to));
				}
			}
		}
		if (dis[t]==inf)break;
		for (int i=0; i<=V; ++i) H[i]+=dis[i];
		int d=f;
		for(int v=t; v!=s; v=PreV[v]) d=min(d,G[PreV[v]][PreE[v]].cap);
		f-=d,flow+=d,res+=d*H[t];
		for (int v=t; v!=s; v=PreV[v]) {
			edge& e=G[PreV[v]][PreE[v]];
			e.cap-=d;
			G[v][e.rev].cap+=d;
		}
	}
	return res;
}
int a[N],T;
int main() {
	scanf("%d",&T);
	while(T--) {
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=1; i<=n; ++i) scanf("%d",&a[i]);
		int ss=0,s=1,t=2*n+2,tt=2*n+3;
		init(tt+1);
		AddEdge(ss,s,k,0);
		AddEdge(t,tt,k,0);
		for(int i=1; i<=n; ++i) {
			AddEdge(s,i+1,1,0);
			AddEdge(i+1+n,t,1,0);
			AddEdge(i+1,i+1+n,1,-a[i]);
			for(int j=i+1; j<=n; ++j) {
				if(a[j]>=a[i]) 	AddEdge(1+i+n,1+j,1,0);
			}
		}
		int ans=0;
		printf("%d\n",-Min_cost_max_flow(ss,tt,inf,ans));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值