有下界的最小费用可行流(bzoj 3876: [Ahoi2014]支线剧情)

来源:互联网 发布:c语言入门知识 编辑:程序博客网 时间:2024/05/19 12:16

什么是有下界的最小费用可行流?

平时来讲都是最小费用最大流,也就是在满流的前提条件下费用尽可能的少,而最小费用可行流一般不要求满流,但是每条边都有最小流量要求(比如经过边e(u,v)的流量不能少于4等等),而你只要满足所有边的最小流量要求就好,在这种情况下求出最小费用

无源汇点的网络:所有点都满足流量平衡

有源汇点的网络:除了源汇点外都满足流量平衡,源点只有流出,汇点只有流入


如何解决这类问题?

当然是将它转成最小费用最大流就好了!

那么怎么转?

先分类:

对于1:无源点汇点求网络可行流

①增加新源点和新汇点

②对于点u,设u所有流出边的下界和为otu,所有流入u的边的下界和为inu,令x=inu-otu,如果x<0,那么从u向汇点连接一条流量为|x|的边,如果x>0,那么从源点向u连接一条流量为x的边

之后求最小费用最大流,如果无法满流,则说明原题根本没有可行流

对于2:有源点汇点的网络可行流

很好办,只要从汇点向源点连一条容量为无穷大且无下界的边,就成第一种情况了


附录:其实以上都是求有下界的最小费用可行流,并没有要求最大流或者最小流

如果有要求的话难度就更高一级别,就先不讲了,分享一个链接

http://blog.csdn.net/water_glass/article/details/6823741


3876: [Ahoi2014]支线剧情

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1811  Solved: 1089
[Submit][Status][Discuss]

Description

【故事背景】
宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等。不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情。这些游戏往往
都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情。
【问题描述】
JYY现在所玩的RPG游戏中,一共有N个剧情点,由1到N编号,第i个剧情点可以根据JYY的不同的选择,而经过不同的支线剧情,前往Ki种不同的新的剧情点。当然如果为0,则说明i号剧情点是游戏的一个结局了。
JYY观看一个支线剧情需要一定的时间。JYY一开始处在1号剧情点,也就是游戏的开始。显然任何一个剧情点都是从1号剧情点可达的。此外,随着游戏的进行,剧情是不可逆的。所以游戏保证从任意剧情点出发,都不能再回到这个剧情点。由于JYY过度使用修改器,导致游戏的“存档”和“读档”功能损坏了,
所以JYY要想回到之前的剧情点,唯一的方法就是退出当前游戏,并开始新的游戏,也就是回到1号剧情点。JYY可以在任何时刻退出游戏并重新开始。不断开始新的游戏重复观看已经看过的剧情是很痛苦,JYY希望花费最少的时间,看完所有不同的支线剧情。

Input

输入一行包含一个正整数N。
接下来N行,第i行为i号剧情点的信息;
第一个整数为Ki,表示与i连接的有Ki个剧情点,接下来Ki个整数对,Bij和Tij,表示从剧情点i可以前往剧
情点j,并且观看这段支线剧情需要花费的时间为Tij。

Output

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

Sample Input

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

Sample Output

24

这题就是给你一个有向无环联通图,除此之外每个点都可以瞬间回到点1,并且1的拓扑序最高

求每条边都经过至少一次的最短总耗时

因为每条边都至少经过一次,那么相当于每条边的下界流量就为1,上届显然无穷大

费用就是这条边的长度,那么就好办了


新建源点汇点

①如果x到y有条长度为z的边,那么x到y连接一条流量inf,费用为z的边(每条边除了必走的1次外可以无限走)

②所有点向点1连接一条流量inf,费用为0的边(因为你可以随时重新开始游戏)

③所有点向汇点连接一条流量为该点出度,费用为0的边

(因为所有边都要至少经过1次,那么对于x点必须要准备好out[x]的流量才行)

④源点向所有点连接一条流量为该点入度,费用为0的边

根据题意一定可行,直接套最小费用最大流模板就好了

注意最后答案加上所有路径的长度,因为每条边必走一次而你算出的费用不包括必走的那一次

(按道理从源点到所有点的边应该是有费用的,源点到x的费用为x所有入边的长度之和,可是这步麻烦省掉了)


204ms

#include<stdio.h>#include<queue>#include<string.h>using namespace std;#define LL long long#define inf 1044266558typedef struct Res{int next;int to, from;int flow, cost;}Road;Road G[90005];int head[505], vis[505], dis[505], in[505], out[505], S, T, cnt, ans; void Add(int u, int v, int flow, int cost){cnt++;G[cnt].next = head[u];head[u] = cnt;G[cnt].from = u;G[cnt].to = v;G[cnt].flow = flow;G[cnt].cost = cost;}int SPFA(){int now, i, v;queue<int> q;memset(vis, 0, sizeof(vis));memset(dis, 62, sizeof(dis));q.push(S);vis[S] = 1;dis[S] = 0;while(q.empty()==0){now = q.front();q.pop();vis[now] = 0;for(i=head[now];i!=0;i=G[i].next){v = G[i].to;if(G[i].flow && dis[v]>dis[now]+G[i].cost){dis[v] = dis[now]+G[i].cost;if(vis[v]==0){vis[v] = 1,q.push(v);}}}}if(dis[T]<15000000)return 1;return 0;}int Sech(int now, int low){int i, w, used;vis[now] = 1;if(now==T)return low;used = low;for(i=head[now];i!=0;i=G[i].next){if(G[i].flow && dis[G[i].to]==dis[now]+G[i].cost && vis[G[i].to]==0){w = Sech(G[i].to, min(used, G[i].flow));G[i].flow -= w;G[i^1].flow += w;used -= w;ans += w*G[i].cost;if(used==0)return low;}}return low-used; }int main(void){int i, j, n, x, y;while(scanf("%d", &n)!=EOF){S = n+2, T = n+1;cnt = 1, ans = 0;memset(in, 0, sizeof(in));memset(out, 0, sizeof(out));for(i=2;i<=n;i++){Add(i, 1, inf, 0);Add(1, i, 0, 0);}for(i=1;i<=n;i++){scanf("%d", &out[i]);for(j=1;j<=out[i];j++){scanf("%d%d", &x, &y);Add(i, x, inf, y);Add(x, i, 0, -y);in[x]++;ans += y;}}for(i=1;i<=n;i++){x = in[i]-out[i];if(x<0){Add(i, T, -x, 0);Add(T, i, 0, 0);}else{Add(S, i, x, 0);Add(i, S, 0, 0);}}while(SPFA()) {memset(vis, 0, sizeof(vis));while(Sech(S, 1044266558))memset(vis, 0, sizeof(vis));}printf("%d\n", ans);}return 0;}



阅读全文
1 0