[ZJOI2010]网络扩容

题目:BZOJ1834、洛谷P2604、codevs1362。

题目大意:给你一些边的容量和将这条边扩充1点容量的费用,求1.点1到n的最大流;2.将最大流扩充k点的最小费用。

解题思路:第一问就是裸最大流。

第二问可以这么做:将原图容量改成INF,超级源点S连容量k费用0的边到1,从n连容量k费用0的边到超级汇点。然后对该图求最小费用最大流就是答案。

因为扩容k并不用考虑原图,只要保证源点到汇点能有k的流量即可,那么此时求最小费用最大流即可。

不过有一点,在第一问跑完最大流后,会剩下一些边,这些边是免费的,所以在考虑第二问的时候,应该在第一问的残余网络上建图。

所以我在求第一问时用的也是费用流,费用是0,然后我们只需要最后的流量即可。接着直接在该图上建新图然后跑最大流即可。

EK过。

C++ Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
using namespace std;
#define min(a,b) (((a)<(b))?(a):(b))
#define C c=getchar()
#define INF 0x3f3f3f3f
struct edges{
    int from,to,cap,cost,nxt;
}e[500005];
int n,m,k,cnt,head[5005],vis[5005],dis[5005],pre_e[5005],a[5005];
int u[5005],v[5005],cap[5005],Cost[5005];
queue<int>q;
inline int readint(){
    char C;
    int p=0;
    for(;!isdigit(c);C);
    for(;isdigit(c);C)p=(p<<3)+(p<<1)+(c^'0');
    return p;
}
inline void addedge(int from,int to,int cap,int cost){
    e[++cnt]=(edges){from,to,cap,cost,head[from]};
    head[from]=cnt;
    e[++cnt]=(edges){to,from,0,-cost,head[to]};
    head[to]=cnt;
}
void SPFA(int s,int t,int& flow,int& cost){
    for(;;){
        memset(vis,0,sizeof vis);
        memset(dis,0x3f,sizeof dis);
        memset(pre_e,0,sizeof pre_e);
        memset(a,0x3f,sizeof a);
        vis[s]=1;
        dis[s]=0;
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].cost&&e[i].cap>0){
                    dis[v]=dis[u]+e[i].cost;
                    pre_e[v]=i;
                    a[v]=min(a[u],e[i].cap);
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        if(dis[t]==INF)return;
        flow+=a[t];
        cost+=a[t]*dis[t];
        for(int i=t;i!=s;i=e[pre_e[i]].from){
            e[pre_e[i]].cap-=a[t];
            e[pre_e[i]^1].cap+=a[t];
        }
    }
}
int main(){
    n=readint(),m=readint(),k=readint();
    cnt=1;
    memset(head,0,sizeof head);
    for(int i=1;i<=m;++i){
        u[i]=readint(),v[i]=readint(),cap[i]=readint(),Cost[i]=readint();
        addedge(u[i],v[i],cap[i],0);
    }
    int flow=0,cost=0;
    SPFA(1,n,flow,cost);
    printf("%d ",flow);
    for(int i=1;i<=m;++i)addedge(u[i],v[i],INF,Cost[i]);
    addedge(0,1,k,0);
    addedge(n,n+1,k,0);
    flow=0,cost=0;
    SPFA(0,n+1,flow,cost);
    printf("%d\n",cost);
    return 0;
}

 

posted @   Mrsrz  阅读(264)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
阅读排行:
· 盘点!HelloGitHub 年度热门开源项目
· DeepSeek V3 两周使用总结
· 02现代计算机视觉入门之:什么是视频
· C#使用yield关键字提升迭代性能与效率
· 回顾我的软件开发经历(1)
点击右上角即可分享
微信分享提示