您的位置:首页 > 其它

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

2017-08-02 20:30 393 查看
什么是有下界的最小费用可行流?
平时来讲都是最小费用最大流,也就是在满流的前提条件下费用尽可能的少,而最小费用可行流一般不要求满流,但是每条边都有最小流量要求(比如经过边e(u,v)的流量不能少于4等等),而你只要满足所有边的最小流量要求就好,在这种情况下求出最小费用
无源汇点的网络:所有点都满足流量平衡
有源汇点的网络:除了源汇点外都满足流量平衡,源点只有流出,汇点只有流入

如何解决这类问题?
当然是将它转成最小费用最大流就好了!
那么怎么转?
先分类:
对于1:无源点汇点求网络可行流
①增加新源点和新汇点
②对于点u,设u所有流出边的下界和为otu,所有流入u的边的下界和为inu,令x=inu-otu,如果x<0,那么从u向汇点连接一条流量为|x|的边,如果x>0,那么从源点向u连接一条流量为x的边
之后求最小费用最大流,如果无法满流,则说明原题根本没有可行流
证明:考虑一条下界为1的边(u, v),上面的操作就同等于直接把这条边删掉,只要保证最后u点会多出1点流量,v点少1点流量就OK,可是怎么样才能保证呢?那就连一条u到汇点容量为1的边,再连一条源点到v点的边并保证这两条边满流!
对于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

62 2 1 3 22 4 3 5 42 5 5 6 6000

Sample Output

24

这题就是给你一个有向无环联通图,除此之外每个点都可以瞬间回到点1,并且1的拓扑序最高
求每条边都经过至少一次的最短总耗时
因为每条边都至少经过一次,那么相当于每条边的下界流量就为1,上届显然无穷大
费用就是这条边的长度,那么就好办了

新建源点汇点
①如果x到y有条长度为z的边,那么x到y连接一条流量inf,费用为z的边(每条边除了必走的1次外可以无限走)
②所有点向点1连接一条流量inf,费用为0的边(因为你可以随时重新开始游戏)
③所有点向汇点连接一条流量为该点出度,费用为0的边
(因为所有边都要至少经过1次,那么对于x点必须要准备好out[x]的流量才行)
④源点向所有点连接一条流量为该点入度,费用为0的边
根据题意一定可行,直接套最小费用最大流模板就好了
别忘了最后答案要加上所有本身流量要求对应的费用之和(正好是所有边的长度和)
因为上面操作相当于删边!边被删了费用自然不会被统计

204ms
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
#define LL long long
#define inf 1044266558
typedef 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: