[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; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· 盘点!HelloGitHub 年度热门开源项目
· DeepSeek V3 两周使用总结
· 02现代计算机视觉入门之:什么是视频
· C#使用yield关键字提升迭代性能与效率
· 回顾我的软件开发经历(1)