zoukankan      html  css  js  c++  java
  • BZOJ 3876 支线剧情

    支线剧情

    【故事背景】

    宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等。不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情。这些游戏往往都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情。

    【问题描述】

    JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为0,则说明i号剧情点是游戏的一个结局了。

    JYY观看一个支线剧情需要一定的时间。JYY一开始处在1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,

    所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。

    【输入格式】

    输入一行包含一个正整数N。

    接下来N行,第i行为i号剧情点的信息;

    第一个整数为,接下来个整数对,Bij和Tij,表示从剧情点i可以前往剧

    情点,并且观看这段支线剧情需要花费的时间。

    【输出格式】

     输出一行包含一个整数,表示JYY看完所有支线剧情所需要的最少时间。

    【样例输入】

    6
    2 2 1 3 2
    2 4 3 5 4
    2 5 5 6 6
    0
    0
    0

    【样例输出】

    24

    【样例解释】

    JYY需要重新开始3次游戏,加上一开始的一次游戏,4次游戏的进程是

    1->2->4,1->2->5,1->3->5和1->3->6。

    对于100%的数据满足N<=300,0<=Ki<=50,1<=Tij<=300,Sigma(Ki)<=5000


    题解:

    题意就是要求走完所有边所需的最小时间(费用)

    相当于有上下界无源汇可行最小费用流

    那么就把题目中给定的边下界设为 1

    重新开始就从每一个点连向点 1 就好了

    具体见图可看代码

    对于超级源与超级汇的连边也一起连在里面了

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 const int maxn = 1e3 + 1;
      9 const int maxm = 3e4 + 1;
     10 const int inf = 1e9 + 7;
     11 int n;
     12 int s, t, nors, nort, sups, supt;
     13 int du[maxn];
     14 int len;
     15 int nex[maxm], fir[maxn], ver[maxm], con[maxm], val[maxm];
     16 bool vis[maxn];
     17 int que[maxm << 1], dis[maxn];
     18 int ans;
     19 inline void Scan(int &x)
     20 {
     21     char c;
     22     bool o = false;
     23     while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
     24     x = c - '0';
     25     while(isdigit(c = getchar())) x = x * 10 + c - '0';
     26     if(o) x = -x;
     27 }
     28 inline void Add(int x, int y, int c, int w)
     29 {
     30     nex[++len] = fir[x];
     31     fir[x] = len;
     32     ver[len] = y;
     33     con[len] = c;
     34     val[len] = w;
     35 }
     36 inline void Ins(int x, int y, int c, int w)
     37 {
     38     Add(x, y, c, w);
     39     Add(y, x, 0, -w);
     40 }
     41 inline void Sup(int x, int y, int l, int r, int w)
     42 {
     43     if(l) du[x] -= l, du[y] += l;
     44     if(l != r) Ins(x, y, r - l, w);
     45 }
     46 inline bool Spfa()
     47 {
     48     int head = 0, tail = 1;
     49     for(int i = 1; i <= supt; ++i)
     50         dis[i] = inf, vis[i] = false;
     51     que[tail] = s;
     52     dis[s] = 0;
     53     vis[s] = true;
     54     while(head < tail)
     55     {
     56         int u = que[++head];
     57         for(int i = fir[u]; i; i = nex[i])
     58         {
     59             if(!con[i]) continue;
     60             int v = ver[i];
     61             if(dis[v] > dis[u] + val[i])
     62             {
     63                 dis[v] = dis[u] + val[i];
     64                 if(!vis[v])
     65                 {
     66                     vis[v] = true;
     67                     que[++tail] = v;
     68                 }
     69             }
     70         }
     71         vis[u] = false;
     72     }
     73     return dis[t] < inf;
     74 }
     75 int Dinic(int u, int f)
     76 {
     77     vis[u] = true;
     78     if(u == t) return f;
     79     int g = f;
     80     for(int i = fir[u]; i; i = nex[i])
     81     {
     82         if(!con[i]) continue;
     83         int v = ver[i];
     84         if(vis[v] || dis[v] != dis[u] + val[i]) continue;
     85         int h = Dinic(v, min(con[i], g));
     86         if(h)
     87         {
     88             con[i] -= h;
     89             con[i ^ 1] += h;
     90             g -= h;
     91             ans += h * val[i];
     92             if(!g) return f;
     93         }
     94     }
     95     return f - g;
     96 }
     97 inline int Flow(int x, int y)
     98 {
     99     s = x, t = y, ans = 0;
    100     while(Spfa()) Dinic(s, inf);
    101     return ans;
    102 }
    103 inline void Init()
    104 {
    105     len = 1;
    106     nors = n << 1 | 1;
    107     nort = nors + 1;
    108     sups = nort + 1;
    109     supt = sups + 1;
    110 }
    111 int main()
    112 {
    113     Scan(n);
    114     int m, x, t;
    115     Init();
    116     for(int i = 1; i <= n; ++i)
    117     {
    118         Scan(m);
    119         Ins(i, supt, m, 0);
    120         while(m--)
    121         {
    122             Scan(x), Scan(t);
    123             Sup(i, x, 1, inf, t);
    124             Ins(sups, x, 1, t);
    125         }
    126         if(i != 1) Ins(i, 1, inf, 0);
    127     }
    128     printf("%d", Flow(sups, supt));
    129 }
  • 相关阅读:
    原创:搜索算法之两个数组取交集的算法
    原创:中文分词的逆向最大匹配算法
    搜索推荐系统根据用户搜索频率(热搜)排序
    原创:Solr Wiki 中关于Suggester(搜索推荐)的简单解读
    从海量文本中统计出前k个频率最高的词语
    原创:从海量数据中查找出前k个最小或最大值的算法(java)
    NOIWC2019 懵逼记
    BZOJ 4568: [Scoi2016]幸运数字(倍增+线性基)
    BZOJ 3207: 花神的嘲讽计划Ⅰ(莫队+哈希)
    BZOJ 3653: 谈笑风生(主席树)
  • 原文地址:https://www.cnblogs.com/lytccc/p/7009007.html
Copyright © 2011-2022 走看看