紫书上网络流部分的第一道例题, 刚刚学了最大流,还没有理解二分图匹配 , 这里就只说一下我用最大流是怎么做的吧 。
我们可以假想一个源点,一个汇点,然后对于每一个设备的插头,从源点连一条线,对于每个插座,连一条线到汇点,且容量都为1 。 然后对于每一个转换器,从原插头到变换后的插头连一条边,因为转换器数量无穷大,所以容量为无穷大 。
这样我们就将原问题抽象成了最大流问题,巧妙的将出入路径的容量赋值为1,以此来让每一个设备匹配到唯一一个容器 。紫书上说这是二分图匹配,也许也暗含着其原理吧 。
最大流问题好像适合解决那种匹配问题, 因为其无序性,我们很难定义阶段,而且状态还有可能回到之前的状态,所以不能运用动态规划解决。
另外通过该题也可以看出,要想应用网络流首先应该将实际问题抽象出来,将具体意义的性质或量抽象成网络流模型中的流量或者容量。
细节参见代码:
#include<bits/stdc++.h> using namespace std; const int INF = 100000000; const int maxn = 505; int T,cnt,n,m,t,k,a[maxn],p[maxn]; char s[maxn],buf[maxn]; map<string,int> pp; struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f) {} }; vector<Edge> edges; vector<int> g[maxn]; void init() { for(int i=0;i<maxn;i++) g[i].clear(); edges.clear(); } void addedge(int from,int to,int cap) { //增加边并将每个节点对应的边保存在g中 edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); t = edges.size(); g[from].push_back(t-2); g[to].push_back(t-1); } int maxflow(int s,int t) { int flow = 0; //最大流初始化为0 for(;;) { //核心算法,需要注意,我们一开始加进来的边的流量都是0,通过求最小残量逐步增广,更新最大流 memset(a,0,sizeof(a)); queue<int> Q; Q.push(s); a[s] = INF; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i=0;i<g[x].size();i++) { Edge& e = edges[g[x][i]]; if(!a[e.to]&&e.cap > e.flow) { p[e.to] = g[x][i]; //记录每次增加流量的路径 a[e.to] = min(a[x],e.cap-e.flow); //求出该道路中所有残量的最小值 Q.push(e.to); } } if(a[t]) break; //到达终点,退出 } if(!a[t]) break; //终点残量为0,不能再增广,break; for(int u=t;u != s; u = edges[p[u]].from) { edges[p[u]].flow += a[t]; //将所求残量加入到该路径中 edges[p[u]^1].flow -= a[t]; //将反向路径减去 } flow += a[t]; //更新总的最大流 } return flow; } int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); init(); pp.clear(); cnt = 1; for(int i=0;i<n;i++) { scanf("%s",s); if(!pp.count(s)) pp[s] = cnt++; addedge(pp[s],500,1); //因为插头种类最大400,故将汇点设为500 } scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%s%s",buf,s); if(!pp.count(s)) pp[s] = cnt++; addedge(0,pp[s],1); //将源点设为0 } scanf("%d",&k); for(int i=0;i<k;i++) { scanf("%s%s",buf,s); if(!pp.count(buf)) pp[buf] = cnt++; if(!pp.count(s)) pp[s] = cnt++; addedge(pp[buf],pp[s],INF); } printf("%d\n",m - maxflow(0,500)); if(T) printf("\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-19 11:19:46