[AHOI2014/JSOI2014]支线剧情

~~~题面~~~

题解:

第一眼费用流,,然后想了好久怎么建图,,,最后发现是最小费用可行流的板子题。。。。

其实还没有很懂这个算法,所以这里只是摆一下步骤,以后再补理解吧。

首先一个思路就是转换图,将有上下限的图变为普通的网络流图,然后再跑费用流。

所以建图其实和有上下界的网络流一样的。。。

1,首先建立超级源点汇点ss和tt

2,对于原图中每一条边x ---> y,设其上下界为(l, r),费用为cost,那么连边的时候将流量变为r - l即可

3,对于任意点i,记d[i]为它的富余流量,即入度的下界和 - 出度的下界和。

  若d[i] > 0,则连边ss ----> i, 流量为d[i] , 费用0

  若d[i] < 0,则连边i ----> t,流量为-d[i],费用0

4,连边t ---> s,流量inf,费用0

答案即为ans + 所有边下界 * 边的费用

其实可以感性的理解为先有了一个不一定合法的解(下界*费用),然后再利用费用流使用最小的代价使得答案合法。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 400
  5 #define ac 100000
  6 #define inf 2139062143
  7 #define getchar() *o++
  8 char READ[5001000], *o = READ;
  9 int n, ans, s, t1, t;
 10 int last[AC], dis[AC], disflow[AC], d[AC];
 11 int date[ac], Next[ac], haveflow[ac], cost[ac], Head[AC], tot = 1;
 12 bool z[AC];
 13 deque<int> q;
 14
 15 inline int read()
 16 {
 17     int x=0;char c=getchar();
 18     while(c > ‘9‘ || c < ‘0‘) c = getchar();
 19     while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar();
 20     return x;
 21 }
 22
 23 inline void add(int f,int w,int S,int C)
 24 {
 25     date[++tot] = w, Next[tot] = Head[f], haveflow[tot] = S, cost[tot] = C, Head[f] = tot;
 26     date[++tot] = f, Next[tot] = Head[w], cost[tot] = -C, Head[w] = tot;
 27     //printf("%d %d %d %d\n",f,w,S,C);
 28 }
 29
 30 void pre()
 31 {
 32     int a,b,c;
 33     n=read();
 34     t1 = n + 1, s = n + 2, t = n + 3;
 35     for(R i=1;i<=n;i++)
 36     {
 37         a=read();
 38         for(R j=1;j<=a;j++)
 39         {
 40             b=read(),c=read();
 41             --d[i], ++d[b];
 42             ans += c;
 43             add(i, b, inf, c);
 44         }
 45     }
 46     for(R i=2;i<=n;i++)
 47         add(i, t1, inf, 0);
 48     for(R i=1;i<=n;i++)
 49     {
 50         if(d[i] > 0) add(s, i, d[i], 0);
 51         if(d[i] < 0) add(i, t, -d[i], 0);
 52     }
 53     add(t1, 1, inf, 0);//是费用为0!
 54 }
 55
 56 inline void aru()
 57 {
 58     int x = t;
 59     while(x != s)
 60     {
 61         haveflow[last[x]] -= disflow[t];
 62         haveflow[last[x] ^ 1] += disflow[t];
 63         x = date[last[x] ^ 1];
 64     }
 65     ans += disflow[t] * dis[t];
 66 }
 67
 68 bool spfa()
 69 {
 70     int x, now;
 71     dis[s] = 0, disflow[s] = inf, z[s] = true;
 72     q.push_front(s);
 73     while(!q.empty())
 74     {
 75         x = q.front();
 76         q.pop_front();
 77         z[x] = false;//标记出列
 78         for(R i=Head[x]; i ;i=Next[i])
 79         {
 80             now = date[i];
 81             if(haveflow[i] && dis[now] > dis[x] + cost[i])
 82             {//要有流量啊
 83                 dis[now] = dis[x] + cost[i];
 84                 last[now] = i;
 85                 disflow[now] = min(disflow[x], haveflow[i]);
 86                 if(!z[now])
 87                 {
 88                     z[now] = true;
 89                     if(!q.empty() && dis[now] < q.front()) q.push_front(now);
 90                     else q.push_back(now);
 91                 }
 92             }
 93         }
 94     }
 95     if(dis[t] != inf) aru();
 96     return dis[t] != inf;
 97 }
 98
 99 bool spfa1()
100 {
101     int x,now;
102     z[s]=true,dis[s]=0,disflow[s]=inf;
103     q.push_front(s);
104     while(!q.empty())
105     {
106         x=q.front();
107         q.pop_front();
108         z[x]=false;
109         for(int i=Head[x]; i ;i=Next[i])
110         {
111             now=date[i];
112             if(haveflow[i] && dis[now]>dis[x]+cost[i])
113             {
114                 dis[now]=dis[x]+cost[i];
115                 last[now]=i;
116                 disflow[now]=min(disflow[x],haveflow[i]);//以点为单位记录到这个点时的流量
117                 if(!z[now])
118                 {
119                     z[now] = true;
120                     q.push_front(now);
121                 }
122                 /*if(!z[now] && now!=t)
123                 {
124                     if(!q.empty() && dis[now]<dis[q.front()])    q.push_front(now);
125                     else q.push_back(now);
126                     z[now]=true;
127                 }*/
128             }
129         }
130     }
131     //更新路径
132     if(dis[t] != inf) aru();
133     return dis[t] != inf;
134 }
135
136 void work()
137 {
138     //printf("%d\n",ans);
139     memset(dis, 127, sizeof(dis));
140     while(spfa())
141         memset(dis, 127, sizeof(dis));
142     printf("%d\n",ans);
143 }
144
145 int main()
146 {
147 //    freopen("in.in","r",stdin);
148     fread(READ, 1, 5000000, stdin);
149     pre();
150     work();
151 //    fclose(stdin);
152     return 0;
153 }

原文地址:https://www.cnblogs.com/ww3113306/p/9176006.html

时间: 2024-11-09 00:59:27

[AHOI2014/JSOI2014]支线剧情的相关文章

bzoj3876 [Ahoi2014&amp;Jsoi2014]支线剧情

3876: [Ahoi2014&Jsoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2180  Solved: 1300[Submit][Status][Discuss] Description [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. [问题描述

3876: [Ahoi2014&amp;Jsoi2014]支线剧情

###Description ###[故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. ###[问题描述] JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点.当然如果为0,则说明i号剧情点是游戏的一个结局了. JYY观看一个支线

bzoj3876: [Ahoi2014&amp;Jsoi2014]支线剧情(上下界费用流)

传送门 一道题让我又要学可行流又要学zkw费用流…… 考虑一下,原题可以转化为一个有向图,每次走一条路径,把每一条边都至少覆盖一次,求最小代价 因为一条边每走过一次,就要付出一次代价 那不就是费用流了么 我们定义每走一次都会对一条边增加1的流量,1然后费用为时间 那么把下界设为1,上界设为inf,跑一个最小费用可行流就可以了 ps:不会可行流的可以去看看这个博客,我觉得写得很不错->这里 1 //minamoto 2 #include<iostream> 3 #include<cs

P4043 [AHOI2014/JSOI2014]支线剧情 上下界费用流

题意: 有个人每次可以从1出发(可以无限次)  走有向边  耗费的时间为有向边的长度   问最少耗费的时间遍历所有的边至少一次 有点像滑雪那题  不过那题求得是最少的次数 这题很显然可以转化为上下界费用流  只要设置边的容量为1-inf 即可 注意: 上下界费用流的答案为: 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) #include<bit

bzoj3876【Ahoi2014】支线剧情

3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 485  Solved: 297 [Submit][Status][Discuss] Description [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. [问题描述] JYY现在所玩

BZOJ 3876 【AHOI2014】 支线剧情

题目链接:支线剧情 这道题就是一道裸裸的上下界网络流--只不过这道题边带了权,那么建出图之后跑费用流即可. 首先需要新建超级源\(S\)和超级汇\(T\).对于这道题,对于一条边\((u,v,z)\),我们从\(S\)向\(v\)连一条容量为\(1\),费用为\(z\)的边,保证下界:从\(u\)向\(T\)连一条容量为\(1\),费用为\(0\)的边,也是用来保证下界的.由于没有上界,所以直接从\(u\)向\(v\)连一条容量为\(INF\),费用为\(z\)的边即可. 注意这道题可以在任意一

[AHOI2014][bzoj3876] 支线剧情 [上下界费用流]

题面 传送门 思路 转化模型:给一张有向无环图,每次你可以选择一条路径走,花费的时间为路径上边权的总和,问要使所有边都被走至少一遍(可以重复),至少需要花费多久 走至少一遍,等价于覆盖这条边 也就是说,我们要找这个图的一个可重复的路径覆盖 路径覆盖让我们想到什么算法了呢? 网络流啊! 我们考虑建立网络流图模型. 这道题里面有个关键:走过一条边,走几次就要花几次的费用,这想到什么? 费用流嘛! 我们定义走一次路径会给这条路径上的所有边增加1的流量,再给所有边赋一个费用等于边权 这样,我们只要设每条

【BZOJ3876】【Ahoi2014】支线剧情 有下界的最小费用最大流

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43025375"); } [BZOJ2324]营救皮卡丘 这道题也是一道有下界的最小费用最大流. 我的题解地址:http://blog.csdn.net/vmurder/article/details/41378979 这道题其实就是模板题. 我的处理

「AHOI2014/JSOI2014」支线剧情

「AHOI2014/JSOI2014」支线剧情 传送门 上下界网络流. 以 \(1\) 号节点为源点 \(s\) ,新建一个汇点 \(t\),如果 \(u\) 能到 \(v\),那么连边 \(u \to v\),下界为 \(1\),上界为 \(+\infty\),费用为对应的所需时间,表示这段剧情至少看一次,且看一次代价为对应的所需时间. 又因为我们可以在任何一个节点重开一次,所以我们的每个节点 \(u\) 都连边 \(u \to t\) ,下界为 \(0\),上界为 \(+\infty\),费