• [SDUT 2414] | 山东省第三届省赛 An interesting game | 最小费用最大流


    评测地址

    题目描述

    Xiao Ming recently designs a little game, in front of player there are N small hillsides put in order, now Xiao Ming wants to increase some hillsides to block the player, so he prepared another M hillsides, but he does not hope it will be too difficult,so only K in M hillsides are selected to add at most. Paying attention to the original N hillsides, between each two can add only one hillside. Xiao Ming expects players from the starting place to reach the destination in turn and passes all the hillsides to make his distance travelled longest. Please help Xiao Ming how to add the hillsides that he prepared. Note: The distance between two hillsides is the absolute value of their height difference.

    输入

    The first line of input is T, (1 <= T <= 100) the number of test cases. Each test case starts with three integers N,M,K (2 <= N <= 1000, 1 <= M <= 1000, 1 <= K <= M and 1 <= K < N), which means that the number of original hillsides, the number of hillsides Xiao Ming prepared and The number of most Xiao Ming can choose from he prepared. Then follow two lines, the first line contains N integers Xi (0 <= Xi <= 30), denoting the height of each original hillside, Note: The first integer is player’s starting place and the last integer is player’s destination. The second line contains M integers Yi (0 <= Yi <= 30), denoting the height of prepared each hillsides.

    输出

    For every test case, you should output "Case k: " first in a single line, where k indicates the case number and starts from 1. Then print the distance player can travel longest.

    样例输入 Copy

    3
    2 1 1
    6 9
    8
    2 1 1
    6 9
    15
    3 2 1
    5 9 15
    21 22
    

    样例输出 Copy

    Case 1: 3
    Case 2: 15
    Case 3: 36
    

    题意:
    给出n个数,这n个数中有n-1个位置,在n-1个位置中插入k个数,k个数来自题目中给定的长度为m的数组,问插入k个数之后,两两之间的差值之和最大是多少:

    思路:
    链接
    最小费用最大流
    预处理出没有处理的情况下的答案 a n s ans ans,即相邻两数之差
    首先设置一个辅助点 S ′ S' S,设置起点为 S S S,终点为 T T T,将起点和辅助点之间连入一条边,限制流量为 k k k,费用为 0 0 0,即题目当中的选择的最大的数量限制,然后将 n − 1 n-1 n1个空隙和辅助点接入容量为 1 1 1,费用为 0 0 0
    对于网络的前半段已经连接成功,现在的问题是怎样连接已有的山坡和要加入的山坡,题目中给定高度的范围在 [ 0 , 30 ] [0,30] [0,30],所以说可以遍历高度,在 n − 1 n-1 n1个间隔和 t t t ( [ 0 , 30 ] ) ([0,30]) ([0,30])个高度之间建立连接,容量为 1 1 1,费用为 − d i s -dis dis(最小费用类似最大生成树的处理方式),然后将 t t t个高度和终点 T T T建立容量为个数 ( c n t [ t ] ) (cnt[t]) (cnt[t]),费用为0的连接,最终求出最小费用最大流即可获得最小的费用 m i n C o s t minCost minCost,然后用 a n s − m i n C o s t ans-minCost ansminCost既是答案

    建出来的的图应该是:
    在这里插入图片描述

    int a[maxn],b[33];
    typedef pair<ll, ll> PLL;
    struct Edge {
    	int u, v, cap, flow, cost;
    	Edge(int _u, int _v, int _cap, int _flow, int _cost) {
    		u = _u, v = _v, cap = _cap, flow = _flow, cost = _cost;
    	}
    };
    struct MinCostMaxFlow {
    	int n, m;
    	vector<Edge> edges;
    	vector<int> G[maxn];
    	int vis[maxn], dis[maxn], p[maxn], a[maxn];
    	void init(int x) {
    		this->n = x;
    		for (int i = 0; i <= x; i++) G[i].clear();
    		edges.clear();
    	}
    	void add(int u, int v, int cap, int cost) {
    		edges.push_back(Edge(u, v, cap, 0, cost));
    		edges.push_back(Edge(v, u, 0, 0, -cost));
    		m = edges.size();
    		G[u].push_back(m - 2);
    		G[v].push_back(m - 1);
    	}
    	bool BellmanFord(int s, int t, ll &flow, ll &cost) {
    		for (int i = 0; i <= n; i++) dis[i] = 0x3f3f3f3f, vis[i] = 0;
    		queue<int> que;
    		que.push(s);
    		dis[s] = 0, vis[s] = 0, p[s] = 0, a[s] = 0x3f3f3f3f;
    		while (que.size()) {
    			int u = que.front();
    			que.pop();
    			vis[u] = 0; /// not in the queue
    			for (int i = 0; i < G[u].size(); i++) {
    				int id = G[u][i];
    				Edge e = edges[id];
    				int to = e.v;
    				if (e.cap > e.flow && dis[to] > dis[u] + e.cost) {
    					dis[to] = dis[u] + e.cost;
    					p[to]   = id;
    					a[to]   = min(a[u], e.cap - e.flow);
    					if (!vis[to]) {
    						que.push(to);
    						vis[to] = 1;
    					}
    				}
    			}
    		}
    		if (dis[t] >= 0x3f3f3f3f) return false;
    		flow += a[t];
    		cost += 1LL * dis[t] * 1LL * a[t];
    		for (int u = t; u != s; u = edges[p[u]].u) {
    			edges[p[u]].flow += a[t];
    			edges[p[u] ^ 1].flow -= a[t];
    		}
    		return true;
    	}
    	PLL MinCostAndMaxFlow(int s, int t) {
    		ll flow = 0;
    		ll cost = 0;
    		while (BellmanFord(s, t, flow, cost));
    		return {flow, cost};
    	}
    } solve;
    int n, m, s, t, tm, tk;
    int main() {
    	int _ = read;
    	for(int I=1; I<=_; I++) {
    		n = read,tm = read,tk = read;
    		solve.init(n + 507);
    		for(int i=0; i<=30; i++) b[i] = 0;
    		for(int i=0; i<n; i++) a[i] = read;
    //		for(int i=1; i<=n; i++) aa[i] = read;
    		for(int i=1; i<=tm; i++) {
    			int x = read;
    			++ b[x];
    		}
    		ll ans = 0;
    		for(int i=1; i<n; i++) {
    			ans += abs(a[i] - a[i-1]);
    			solve.add(0,i,1,0);
    			for(int j=0; j<=30; j++) {
    				if(b[j]) {
    					ll dis = abs(a[i] - j) + abs(a[i-1]-j) -
    					         abs(a[i]-a[i-1]);
    					solve.add(i,n+j,1,-dis);
    				}
    			}
    		}
    		int st = n + 33;
    		int ed = st + 1;
    		for(int i=0; i<=30; i++) {
    			if(b[i]) solve.add(i+n,ed,b[i],0);
    		}
    		solve.add(st,0,tk,0);
    		PLL tmp = solve.MinCostAndMaxFlow(st,ed);
    		printf("Case %d: %lld\n",I,ans - tmp.second);
    	}
    	return 0;
    }
    /**
    3
    2 1 1
    6 9
    8
    2 1 1
    6 9
    15
    3 2 1
    5 9 15
    21 22
    
    **/
    
    
  • 相关阅读:
    第二阶段Sprint冲刺会议8
    第二阶段Sprint冲刺会议7
    第二阶段Sprint冲刺会议6
    问题账户需求分析
    2016年秋季个人阅读计划
    应该怎么做需求分析--读后感
    个人总结
    人月神话第三篇阅读笔记
    第十六周学习进度
    人月神话第二篇阅读笔记
  • 原文地址:https://www.cnblogs.com/PushyTao/p/16196752.html
Copyright © 2020-2023  润新知