1. 程式人生 > >洛谷 P2604 [ZJOI2010]網絡擴容 解題報告

洛谷 P2604 [ZJOI2010]網絡擴容 解題報告

流量 兩個 mem sizeof 表示 初始 pre 答案 while

P2604 [ZJOI2010]網絡擴容

題目描述

給定一張有向圖,每條邊都有一個容量C和一個擴容費用W。這裏擴容費用是指將容量擴大1所需的費用。求: 1、 在不擴容的情況下,1到N的最大流; 2、 將1到N的最大流增加K所需的最小擴容費用。

輸入輸出格式

輸入格式:

輸入文件的第一行包含三個整數N,M,K,表示有向圖的點數、邊數以及所需要增加的流量。 接下來的M行每行包含四個整數u,v,C,W,表示一條從u到v,容量為C,擴容費用為W的邊。

輸出格式:

輸出文件一行包含兩個整數,分別表示問題1和問題2的答案。

說明

30%的數據中,N<=100

100%的數據中,N<=1000,M<=5000,K<=10


k這麽小,開始以為是分層圖搞事呢。

第一問裸的最大流。

第二問我們對初始的每條邊新建一條費用邊,容量為inf,表示隨便用,單位費用就連初始費用,表示要花錢。

保證增加的流量為k,我們搞一個超級源點容量為k連原源點1。

在跑完最大流之後的殘余網絡上跑最小費用最大流。

之前對最大流求法中的反悔理解的不深刻,在寫這個題的時候一直覺得直接跑殘量網絡失去了對原來最大流的反悔機會。但實際上,基於路徑交換的反悔原理,直接跑殘量網絡是沒問題的。

代碼裏面偷了懶,萬一有免費的邊就錯了


Code:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N=1010;
const int M=10010;
const int inf=0x3f3f3f3f;
int head[N],edge[M<<1],cost[M<<1],to[M<<1],Next[M<<1],cnt=1;
void add(int u,int v,int w,int c)
{
    edge[++cnt]=w;cost[cnt]=c;Next[cnt]=head[u];to[cnt]=v;head[u]=cnt;
    edge[++cnt]=0;cost[cnt]=-c;Next[cnt]=head[v];to[cnt]=u;head[v]=cnt;
}
int maxflow,n,m,k;
int dep[N];
bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[1]=1;
    queue <int > q;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=Next[i])
        {
            int v=to[i];
            if(!cost[i]&&!dep[v]&&edge[i])
            {
                dep[v]=dep[u]+1;
                if(v==n) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
int dfs(int now,int flow)
{
    if(now==n) return flow;
    int rest=flow,k;
    for(int i=head[now];i&&rest;i=Next[i])
    {
        int v=to[i];
        if(!cost[i]&&edge[i]&&dep[v]==dep[now]+1)
        {
            k=dfs(v,min(rest,edge[i]));
            if(!k) dep[v]=0;
            rest-=k;
            edge[i]-=k;
            edge[i^1]+=k;
        }
    }
    return flow-rest;
}
void Dinic()
{
    int flow=0;
    while(bfs())
        while(flow=dfs(1,inf)) maxflow+=flow;
    printf("%d ",maxflow);
}
int pre[N],used[N],dis[N];
int spfa()
{
    queue <int > q;
    q.push(0);
    memset(dis,0x3f,sizeof(dis));
    dis[0]=0;
    while(!q.empty())
    {
        int u=q.front();
        used[u]=0;
        q.pop();
        for(int i=head[u];i;i=Next[i])
        {
            int v=to[i];
            if(edge[i]&&dis[v]>dis[u]+cost[i])
            {
                dis[v]=dis[u]+cost[i];
                pre[v]=i;
                if(!used[v])
                    used[v]=1,q.push(v);
            }
        }
    }
    return dis[n]!=inf;
}
void costflow()
{
    int ans=0;
    while(spfa())
    {
        int mi=inf;
        for(int now=n;now;now=to[pre[now]^1])
            mi=min(edge[pre[now]],mi);
        ans+=dis[n]*mi;
        for(int now=n;now;now=to[pre[now]^1])
            edge[pre[now]]-=mi,edge[pre[now]^1]+=mi;
    }
    printf("%d\n",ans);
}
void init()
{
    scanf("%d%d%d",&n,&m,&k);
    int u,v,w,c;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&u,&v,&w,&c);
        add(u,v,w,0),add(u,v,inf,c);
    }
}
void work()
{
    Dinic();
    add(0,1,k,0);
    costflow();
}
int main()
{
    init();
    work();
    return 0;
}

2018.7.14

洛谷 P2604 [ZJOI2010]網絡擴容 解題報告