[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,

评测地址


题目描述


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个数之后,两两之间的差值之和最大是多少:


思路:


链接

最小费用最大流

预处理出没有处理的情况下的答案 ans,即相邻两数之差

首先设置一个辅助点 S',设置起点为S ,终点为T ,将起点和辅助点之间连入一条边,限制流量为k ,费用为0 ,即题目当中的选择的最大的数量限制,然后将 n−1 个空隙和辅助点接入容量为1,费用为0


对于网络的前半段已经连接成功,现在的问题是怎样连接已有的山坡和要加入的山坡,题目中给定高度的范围在 [0,30],所以说可以遍历高度,在 n−1 个间隔和t ( [ 0 , 30 ] ) 个高度之间建立连接,容量为1 ,费用为 −dis(最小费用类似最大生成树的处理方式),然后将t 个高度和终点T 建立容量为个数 (cnt[t]),费用为0的连接,最终求出最小费用最大流即可获得最小的费用 minCost,然后用 ans−minCost既是答案


建出来的的图应该是:

d684fcb88b104fafa2f5d28cc6482591.png


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
**/



目录
相关文章
|
6月前
|
Java
leetcode-452:用最少数量的箭引爆气球
leetcode-452:用最少数量的箭引爆气球
60 0
|
27天前
|
测试技术 定位技术 C++
第十四届省赛大学B组(C/C++)岛屿个数
第十四届省赛大学B组(C/C++)岛屿个数
|
5月前
|
存储 算法 测试技术
力扣经典150题第五十题:用最少数量的箭引爆气球
力扣经典150题第五十题:用最少数量的箭引爆气球
24 0
|
6月前
|
Java 测试技术
HDU-1233-还是畅通工程
HDU-1233-还是畅通工程
35 0
|
6月前
【每日一题Day320】LC2651计算列车到站时间 | 数学
【每日一题Day320】LC2651计算列车到站时间 | 数学
43 0
|
12月前
|
算法 Java
代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球
代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球
63 0
|
机器学习/深度学习 人工智能
1320:【例6.2】均分纸牌(Noip2002) 2020-11-30
1320:【例6.2】均分纸牌(Noip2002) 2020-11-30
108 0
|
测试技术
洛谷P8601[蓝桥杯][2013年第四届真题]剪格子
洛谷P8601[蓝桥杯][2013年第四届真题]剪格子
77 0
畅通工程 HDU - 1232
畅通工程 HDU - 1232
76 0