bzoj1834

第一问很好搞。第二问事实上可以这么想。如果一条边的流量还有,那么我们走过去不要钱,否则要钱,于是跑个费用流,就好了

(其实跑k次spfa也可以,我是这么写的)

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
struct edge
{
    int to,nxt,f,c;
}e[10010];
int n,m,k,cnt=1,ans;
int g[10010],prev[10010],pree[10010],dist[10010],used[10010];
void link(int u,int v,int f,int c)
{
    e[++cnt].nxt=g[u];
    g[u]=cnt;
    e[cnt].to=v;
    e[cnt].f=f;
    e[cnt].c=c;
}
inline void ins(int u,int v,int f,int c)
{
    link(u,v,f,c); link(v,u,0,inf);
}
inline int Min(int x,int y)
{
    return x<y?x:y;
}
bool bfs()
{
    queue<int>q;
    memset(dist,inf,sizeof(dist));
    dist[1]=0;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=g[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(e[i].f&&dist[v]==inf)
            {
                dist[v]=dist[u]+1;
                q.push(v);
            }
        }
    }
    return dist[n]!=inf;
}
int dfs(int u,int delta)
{
    if(u==n) return delta;
    int ret=0;
    for(int i=g[u];i&&delta;i=e[i].nxt)
    {
        int v=e[i].to;
        if(dist[v]==dist[u]+1&&e[i].f)
        {
            int dd=dfs(v,Min(e[i].f,delta));
            delta-=dd;
            e[i].f-=dd;
            e[i^1].f+=dd;
            ret+=dd;
        }
    }
    return ret;
}
void spfa()
{
    queue<int>q;
    memset(dist,inf,sizeof(dist));
    memset(used,0,sizeof(used));
    dist[1]=0;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        used[u]=0;
        for(int i=g[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if((dist[v]>dist[u]&&e[i].f>0)||(dist[v]>dist[u]+e[i].c)&&e[i].f==0)
            {
                if(e[i].f>0) dist[v]=dist[u];
                else dist[v]=dist[u]+e[i].c;
                prev[v]=u;
                pree[v]=i;
                if(!used[v])
                {
                    used[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
int MinCost()
{
    int u=n,ret=0;
    while(u!=1)
    {
        if(e[pree[u]].f>0) e[pree[u]].f--;
        u=prev[u];
    }
    return dist[n];
}
inline void MinCostFlow()
{
    ans=0;
    while(k--)
    {
        spfa();
        ans+=MinCost();
    }
    printf("%d",ans);
}
inline void dinic()
{
    while(bfs())
    {
        ans+=dfs(1,inf);
    }
    printf("%d ",ans);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++)
    {
        int u,v,f,c; scanf("%d%d%d%d",&u,&v,&f,&c);
        ins(u,v,f,c);
    }
    dinic();
    MinCostFlow();
    return 0;
}
时间: 2024-10-12 18:29:57

bzoj1834的相关文章

【BZOJ1834】network 网络扩容(最大流,费用流)

题意:给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用. 求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 30%的数据中,N<=100 100%的数据中,N<=1000,M<=5000,K<=10 思路:RYZ作业 第一问最大流即可 第二问网上很多题解都是在第一问的残余网络上构图,但是根本不需要 考虑边(x,y,z,w) 有容量为z,费用为0的免费流量,有容量为INF,费用为w的扩容付费流

bzoj1834: [ZJOI2010]network 网络扩容

努力看了很久样例一直过不了...然后各种输出中间过程啊巴拉巴拉弄了1h,没办法了...然后突然想到啊原来的边可以用啊为什么不用...于是A了...感人肺腑 #include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n

【bzoj1834】[ZJOI2010]network 网络扩容 最大流+最小费用流

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 样例输入 5 8 2 1 2 5 8 2 5 9

bzoj1834: [ZJOI2010]network 网络扩容

这道题分为俩步,第一是求最大流,第二是在第一问的残量网络上求最小费用流. 建图时俩个点直接连2条边,一条容量为f[i],费用为0,另一条容量为inf,费用为c[i].这样就可以跑俩个算法了 第二问设一个虚拟源点S与1连容量为k,费用为0的边,n与一个虚拟汇点T连容量为k,费用为0的边.这样一直跑,最后只会增加k的流量. 记住bool一定要用true和false,用0和1tle了..不知道为啥,但一定要记住 #include<cstdio> #include<algorithm> #

bzoj1834:最大流+最小费用最大流

为什么昨天看的时候就一直看不懂,果然智商是硬伤...然后今晚一看就懂了OrzOrz,关键是限制容量那个技巧... -------------------------------------------------------------------------------------------- #include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<

【BZOJ1834】 [ZJOI2010]network 网络扩容

Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. Input 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. Output 输出文件一行包含两个整数,分别表示问题1和问题2的答案. Sample Inpu

【最大流】【费用流】bzoj1834 [ZJOI2010]network 网络扩容

引用题解: 最大流+费用流. 第一问最大流即可. 第二问为“最小费用最大流”. 由题意,这一问的可转化为在上一问的“残量网络”上,扩大一些边的容量,使能从新的图中的最大流为k. 那么易得:对于还有剩余流量的边,走过他们的费用为0.而“增加流量”可变为:对残留网络上的每一条边建一条容量是∞费用是w的边.这表示从这些边走,每一流量的费用为w,这就符合题意了. 最后建一个超级源点,从超级源向1建一条容量为k,费用为0的边,就可进行最小费用最大流算法. #include<cstdio> #includ

[ZJOI2010][bzoj1834] 网络扩容 [费用流]

题面 传送门 思路 第一问:无脑网络流跑一波 第二问: 先考虑一个贪心的结论:扩容出来的扩容流量一定要跑满 证明显然 因此我们可以把扩容费用可以换个角度思考,变成增加一点流量,花费W的费用 这样,我们就得到了一个最小费用流的模型 只要在原图基础上,对于每个原图边,加一条费用为W,无限容量的边,而原图中的所有边费用为0,就可以模拟原题需要的情况了 最后一个问题:流量增加限制K怎么处理? 我们虽然可以用spfa的费用流,一次一次增加,直到K,但是这样也太慢chou了吧? 不怕,我们加一个n+1号点,

bzoj1834 网络扩容 网络流

好久没写题解了啊··· 题目大意: 给你一幅n个点的网络,先求出其1到n的最大流,每条弧还会有个属性\(cost_i\),表示没扩容一个单位的费用,现在我们要求的就是扩容K个单位的最小费用 思路: 这是一道比较裸的网络流,第一问直接dinic就是了,重点就在于第二问.我们把第一问的残量网络继续利用,其中的每条弧的费用都是0,此时我们再在第\(i\)条弧的两端之间在建一条弧,弧的容量是\(INF\),费用就是\(cost_i\).这样我们固然可以保证费用正确,可是我们保证不了扩容了K,我们就可以建