zoukankan      html  css  js  c++  java
  • hdu6611----费用流

    K Subsequence

    题意:给定一个长度为(n)的数字序列,现可以从中选取k个单调上升的子序列,且每个元素至多只能被选中一次,问k个子序列元素和的最大值。

    题解:对数列每一项拆点,连接流量为1,费用为(-a[i])的边,所有项的右端点与其后大于等于这一项的项的左端点连流量1,费用0的边。源点与汇点再分别与各项左右端点连边。超级源点与源点连流量k费用0的边。跑最小费用最大流。

    #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;
    } 
    
  • 相关阅读:
    第六周总结&第四次实验报告
    课程总结
    第十四周课程总结&实验报告
    第十三周课程总结
    第十二周课程总结
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
  • 原文地址:https://www.cnblogs.com/vege-chicken-rainstar/p/11538135.html
Copyright © 2011-2022 走看看