BZOJ1834network 网络扩容

1834: [ZJOI2010]network 网络扩容
Time Limit: 3 Sec Memory Limit: 64 MB
Submit: 2334 Solved: 1174
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 Input
5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1
Sample Output
13 19
HINT
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
Source
Day1
最大流+最小费用最大流。。
其实是一个模板题,我却因为一个SB的连边卡了好久。。
第一次打zkw费用流。。
第一问直接建图跑最大流即可。。
第二问在第一问上的残留网络上连边,对每条边连一个容量为+∞,费用为0的边,建一个超级源点,源点和1连一条容量为k,费用为0的边,然后跑zkw费用流即可。。
让DaD3zZ神犇和Claris学长看了好久没有看出端倪。。果然是我太弱。。
附上本蒟蒻的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
struct node
{
    int to,next,v,c,from,t;
};
node edge[1000001];
int h[1000001],q[1000001],dis[1000001],head,tail,cnt=1,n,m,k,tmp=0,ans=0,sum=0,num;
bool mark[1000001],vis[1000001];

int read()
{
    int w=0;
    char ch=getchar();
    while (ch>='0' && ch<='9')
      {
        w=w*10+ch-'0';
        ch=getchar();
      }
    return w;
}

void add1(int u,int v,int w,int cost)
{
    cnt++;
    edge[cnt].next=h[u];
    edge[cnt].from=u;
    h[u]=cnt;
    edge[cnt].to=v;
    edge[cnt].v=w;
    edge[cnt].t=cost;
}

void add2(int u,int v,int w,int cost)
{
    cnt++;
    edge[cnt].next=h[u];
    edge[cnt].from=u;
    edge[cnt].to=v;
    h[u]=cnt;
    edge[cnt].v=w;
    edge[cnt].c=cost;
}

bool bfs()
{
    int j,p;
    memset(dis,-1,sizeof(dis));
    q[1]=1;
    dis[1]=0;
    head=0;
    tail=1;
    while (head<tail)
      {
        head++;
        j=q[head];
        p=h[j];
        while (p)
          {
            if (dis[edge[p].to]<0 && edge[p].v>0)
              {
                  dis[edge[p].to]=dis[j]+1;
                  tail++;
                  q[tail]=edge[p].to;
              }
            p=edge[p].next;
          }
      }
    if (dis[n]>0)
      return true;
    else
      return false;
}

int dfs1(int x,int f)
{
    int w,used=0,i=h[x];
    if (x==n)
      return f;
    while (i)
      {
        if (edge[i].v && dis[edge[i].to]==dis[x]+1)
          {
            w=f-used;
            w=dfs1(edge[i].to,min(w,edge[i].v));
            edge[i].v-=w;
            edge[i^1].v+=w;
            used+=w;
            if (used==f)
              return f;
          }
        i=edge[i].next;
      }
    if (!used)
      dis[x]=-1;
    return used;
}

bool spfa()
{
    int i,now;
    memset(vis,false,sizeof(vis));
    for (i=0;i<=n;i++)
      dis[i]=0x7fffffff;
    head=0;
    tail=1;
    q[0]=n;
    vis[n]=true;
    dis[n]=0;
    while (head<tail)
      {
        now=q[head];
        head++;
        vis[now]=false;
        for (i=h[now];i;i=edge[i].next)
          if (edge[i^1].v && dis[now]-edge[i].c<dis[edge[i].to])
            {
              dis[edge[i].to]=dis[now]-edge[i].c;
              if (!vis[edge[i].to])
                {
                  vis[edge[i].to]=true;
                  q[tail]=edge[i].to;
                  tail++;
                }
            }
      }
    return dis[0]!=0x7fffffff;
}

int dfs2(int x,int f)
{
    int w,used=0,i;
    mark[x]=true;
    if (x==n)
      return f;
    for (i=h[x];i;i=edge[i].next)
      if (dis[edge[i].to]==dis[x]-edge[i].c && edge[i].v && !mark[edge[i].to])
        {
            w=f-used;
            w=dfs2(edge[i].to,min(w,edge[i].v));
            sum+=w*edge[i].c;
            edge[i].v-=w;
            edge[i^1].v+=w;
            used+=w;
            if (used==f)
              return f;
        }
    return used;
}

int main()
{
    int i,u,v,flow,cost;
    n=read();
    m=read();
    k=read();
    for (i=1;i<=m;i++)
      {
        u=read();
        v=read();
        flow=read();
        cost=read();
        add1(u,v,flow,cost);
        add1(v,u,0,-cost);
      }
    while (bfs())
      while (sum=dfs1(1,0x7fffffff))
        ans+=sum;
    num=cnt;
    for (i=2;i<=num;i+=2)
      {
        add2(edge[i].from,edge[i].to,0x7fffffff,edge[i].t);
        add2(edge[i].to,edge[i].from,0,-edge[i].t);
      }
    add1(0,1,k,0);
    add1(1,0,0,0);
    sum=0;
    while (spfa())
      {
        mark[n]=true;
        while (mark[n])
          {
            memset(mark,false,sizeof(mark));
            tmp+=dfs2(0,0x7fffffff);
          }
      }
    printf("%d %d",ans,sum);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值