出题人题解 | #小D的剑阵#

小D的剑阵

https://ac.nowcoder.com/acm/problem/22617

原题解链接:https://ac.nowcoder.com/discuss/154293

先将w,v0,v1 w,v_0,v_1 求和,然后将选择/不选择视为在此基础上付出代价,问题就转化为了求最小代价。

对于每个约束,考虑如下的一个图,s,ts, t表示源点和汇点,x,y x, y表示跟这个约束相关的两把剑,a,b,c,d,e,f a,b,c,d,e,f表示权值

将割掉s s到某一把剑x x的边视为不选择x x ,割掉x xt t的边视为选择xx

要使s,t s,t不连通,割有四种a,cb,da,e,dc,f,b a,c,b,d,a,e,d,c,f,b(注意逗号)

alt

w0w_0 表示选择x x能得到的攻击力, 表示选择y y能得到的攻击力,v0v_0 ​ 表示 都选时额外获得的攻击力,v1v_1 ​ 表示x,y x,y都不选时额外获得的攻击力,v2v_2 ​ 表示只选一个时扣除的攻击力

可得

a+c=w0+w1+v0(x,ya+c=w_{0}+w_{1}+v_{0}(\mathrm{x}, \mathrm{y}, 都不选 ))

b+d=v1(x,yb+d=v_{1}(\mathrm{x}, \mathrm{y} 都选 ))

a+e+d=w0+v0+v1+v2a+e+d=w_{0}+v_{0}+v_{1}+v_{2} (不选 x\mathrm{x} ,选 y\mathrm{y} )

c+f+b=w1+v0+v1+v2c+f+b=w_{1}+v_{0}+v_{1}+v_{2} (选 x\mathrm{x} ,不选 y\mathrm{y} )

只需要求出一组合法的解,人为构造

e=f=v0+v12+v2,b=d=v12,a=w0+v02,c=w1+v02e=f=\frac{v 0+v 1}{2}+v_{2}, b=d=\frac{v 1}{2}, a=w_{0}+\frac{v 0}{2}, c=w_{1}+\frac{v 0}{2}

最小代价即这张图的最小割

复杂度取决于使用的网络流算法,不过应该是都能通过的

#include <bits/stdc++.h>
using namespace std;

typedef long long lo;

lo n, m, opt, lx, ly, tot = -1, head[1007], he[1007], q[1007], t, de[1007], w[1007], W[1007], ans, v0, v1, v2;

struct in
{
  lo to, ne; lo co;
};
vector<in>ter;

inline void build(lo f, lo l, lo c)
{
  ter.push_back((in) {l, head[f], c}), head[f] = ++tot;
}

inline bool bfs()
{
  queue<int>q;
  memset(de, 0, sizeof(de)), de[0] = 1; q.push(0);
  while (!q.empty()) {
    lo qaq = q.front(); q.pop();
    for (lo i = head[qaq]; i >= 0; i = ter[i].ne)
    {
      lo to = ter[i].to;
      if (ter[i].co && (!de[to]))
        de[to] = de[qaq] + 1, q.push(to);
    }
  }
  return de[t] > 0;
}

lo dfs(lo no, lo fl)
{
  if (no == t || (!fl))
    return fl;
  lo rt = 0, c;
  for (lo &i = he[no]; i >= 0; i = ter[i].ne)
  {
    lo to = ter[i].to;
    if (ter[i].co && de[to] == de[no] + 1)
    {
      c = dfs(to, min(fl, ter[i].co));
      if (c)
      {
        fl -= c, rt += c, ter[i].co -= c, ter[i ^ 1].co += c;
        if (fl <= 0)
          return rt;
      }
    }
  }
  return rt;
}

bool flag[1007];

int main()
{
  scanf("%lld%lld", &n, &m);
  t = n + 1; memset(head, -1, sizeof(head));
  for (int i = 1; i <= n; i ++)
    scanf("%lld", w + i), ans += w[i];
  for (int i = 1; i <= m; i ++)
  {
    scanf("%lld%lld%lld%lld%lld", &lx, &ly, &v0, &v1, &v2);
    ans += v0 + v1;
    W[lx] += v1 / 2, W[ly] += v1 / 2, w[lx] += v0 / 2, w[ly] += v0 / 2;
    build(lx, ly, (v0 + v1) / 2 + v2), build(ly, lx, (v0 + v1) / 2 + v2);
  }
  for (int i = 1; i <= n; i ++)
    build(0, i, w[i]), build(i, 0, 0), build(i, t, W[i]), build(t, i, W[i]);
  lo tmp;
  while (bfs())
  {
    memcpy(he, head, sizeof(he));
    while ((tmp = dfs(0, 1e13 + 7)) > 0)
      ans -= tmp;
  }
  printf("%lld", ans);
  return 0;
}


全部评论

相关推荐

来个大佬救一下,为上投了都是石沉大海了,没实习经历的话怕秋招直接进不了面。什么实习这么难找,基本
心态爆炸了:现在正式的岗位都少,实习基本不咋招的,除了大厂,中小企业其实没那么多岗位需求,就算是有,大多都是招一两个廉价劳动力,同时,他们也会希望你一来就能干活的,没时间培训你,就让你了解公司的项目,你了解完就可以开始干活。再者是,很多低质量的实习其实用处没有那么大的。我去年也是找实习找到破防,最后去了一家深圳的小公司实习,工作对我来说很简单,甚至不如我在学校做的项目,秋招的时候,这段实习经历也并没有帮上什么忙,投递简历,依旧非常低的回复率。低回复率是常态,尤其是找实习,找不到,那就把重心放在优化自己的简历和项目,多看八股文,锻炼自己的面试能力,多看别人的面经,自己模拟面试,等秋招的时候,只要有那么寥寥几次,好好抓住那几次机会。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务