标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2247 Accepted Submission(s): 940
大致题意:
给出一个又n个点,m条边组成的无向图。给出两个点s,t。对于图中的每个点,去掉这个点都需要一定的花费。求至少多少花费才能使得s和t之间不连通。
大致思路:
最基础的拆点最大流,把每个点拆作两个点 i 和 i‘ 连接i->i‘费用为去掉这个点的花费,如果原图中有一条边a->b则连接a‘->b。对这个图求出最大流即可。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int VM=420; const int EM=500010; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[EM]; int n,m,src,des,cnt,head[VM]; int dep[VM]; void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; edge[cnt].to=cu; edge[cnt].cap=0; edge[cnt].nxt=head[cv]; head[cv]=cnt++; } int BFS(){ queue<int> q; while(!q.empty()) q.pop(); memset(dep,-1,sizeof(dep)); dep[src]=0; q.push(src); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i].cap>0 && dep[v]==-1){ dep[v]=dep[u]+1; q.push(v); } } } return dep[des]!=-1; } int DFS(int u,int minx){ if(u==des) return minx; int tmp; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i].cap>0 && dep[v]==dep[u]+1 && (tmp=DFS(v,min(minx,edge[i].cap)))){ edge[i].cap-=tmp; edge[i^1].cap+=tmp; return tmp; } } dep[u]=-1; return 0; } int Dinic(){ int ans=0,tmp; while(BFS()){ while(1){ tmp=DFS(src,INF); if(tmp==0) break; ans+=tmp; } } return ans; } int main(){ int s,t; while(~scanf("%d%d",&n,&m)){ cnt=0; memset(head,-1,sizeof(head)); scanf("%d%d",&s,&t); src=0, des=2*n+1; addedge(src,s,INF); addedge(n+t,des,INF); int u,v,w; for(int i=1;i<=n;i++){ scanf("%d",&w); addedge(i,n+i,w); addedge(n+i,i,w); } for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); addedge(n+u,v,INF); //注意这里的建边,src--->s--->u(某条边)---->n+u(拆分u点后的另一点)---->v---->n+v(拆分v点后的另一点)---->u----- addedge(n+v,u,INF); //所以,addedge(n+u,v,INF);仔细想想,这样才能保证 u 和 v 使连接着的 } printf("%d\n",Dinic()); } return 0; }
hdu 4289 网络流拆点,类似最小割(可做模板)邻接矩阵实现
标签:
原文地址:http://www.cnblogs.com/13224ACMer/p/4729570.html