【POJ3281 Dining 】最大流
2011-03-30 14:27
295 查看
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #define CLR(arr,val) memset(arr,val,sizeof(arr)) using namespace std; const int INF=1000000000; template<int MAX> class SapMaxFlow { public: int cap[MAX][MAX],h[MAX],flow[MAX][MAX];// cap表示容量矩阵,需要是0序图 h表示到汇点的距离 int v;//v表示包括源与汇的所有结点的数量 int GetMaxFlow(int s,int t) { int total_flow=0; init(t); int cur = s, i; CLR(low,0); while(h[s] < v) { low[s] = INF; for(i = 0; i != v; i++) if(cap[cur][i] - flow[cur][i] > 0 && h[cur] == h[i] + 1) //如果找到允许弧 { low[i] = min(cap[cur][i] - flow[cur][i], low[cur]); pre[i] = cur; cur = i; if(cur == t) //找到一条最短增广路 { total_flow += low[t]; while(cur != s) { flow[pre[cur]][cur]+=low[t]; flow[cur][pre[cur]]-=low[t]; cur=pre[cur]; } CLR(low,0); } break; } if(i == v) //如果没有找到允许弧 { int minh=INF; for(int j = 0; j != v; j++) if(cap[cur][j] - flow[cur][j] > 0 && minh > h[j]+1) minh=h[j]+1; h[cur]=minh; if(cur != s) cur = pre[cur]; } } return total_flow; } private: int q[MAX],low[MAX],pre[MAX]; void init(int t) { int head = 0, tail = 0, cur; CLR(h,0); q[++tail]=t; while(head < tail) { cur=q[++head]; for(int i=0;i!=v;i++) if(!h[i] && cap[i][cur]-flow[i][cur]>0) //由于可能由初始流,所以减去flow[i][cur] q[++tail]=i,h[i]=h[cur]+1; } } }; SapMaxFlow<410> g; int main() { //freopen("in.txt","r",stdin); int N,F,D,f,d,n; scanf("%d%d%d",&N,&F,&D); int s=2*N+F+D,t=s+1; g.v=s+2; for(int i=0;i!=N;i++) g.cap[i][i+N]=1; for(int i=0;i!=F;i++) g.cap[s][i+2*N]=1; for(int i=0;i!=D;i++) g.cap[i+2*N+F][t]=1; for(int i=0;i!=N;i++) { scanf("%d%d",&f,&d); for(int j=0;j!=f;j++) { scanf("%d",&n); g.cap[2*N+n-1][i]=1; } for(int j=0;j!=d;j++) { scanf("%d",&n); g.cap[i+N][2*N+n+F-1]=1; } } cout<<g.GetMaxFlow(s,t)<<endl; }构图比较巧妙,数据量不大,直接用EK就能过
构图时
源->食物->牛->牛->饮料->汇
任意边容量都是1
不能构成“源->食物->牛->饮料->汇”,因为这样构图不能保证每头牛都只吃一份。
以上是用的EK算法
下面又用SAP写了下:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<climits> using namespace std; const int MAX=410; int cap[MAX][MAX],flow[MAX][MAX]; bool visited[MAX]; //0序图下方可正常工作 int augment(int s,int t,int v,int contain[MAX][MAX],int flow[MAX][MAX]) { memset(visited,0,sizeof(visited)); vector<int> father,dq,minf; dq.push_back(s); father.push_back(-1); minf.push_back(INT_MAX); int cur=0; while(cur!=dq.size()) { for(int i=0;i!=v;i++) { if(contain[dq[cur]][i]-flow[dq[cur]][i]>0 && !visited[i]) { visited[i]=true; if(i==t) { int minflow=min(contain[dq[cur]][i]-flow[dq[cur]][i],minf[cur]); flow[dq[cur]][t]+=minflow; flow[t][dq[cur]]-=minflow; while(father[cur]!=-1) { flow[dq[father[cur]]][dq[cur]]+=minflow; flow[dq[cur]][dq[father[cur]]]-=minflow; cur=father[cur]; } return minflow; } dq.push_back(i); father.push_back(cur); minf.push_back(min(contain[dq[cur]][i]-flow[dq[cur]][i],minf[cur])); } } cur++; } return 0; } int GetMaxFlow(int s,int t,int v,int contain[MAX][MAX],int flow[MAX][MAX]) { int sum=0,ret; while(ret=augment(s,t,v,contain,flow)) sum+=ret; return sum; } int main() { //freopen("in.txt","r",stdin); int N,F,D,f,d,n; scanf("%d%d%d",&N,&F,&D); int s=2*N+F+D,t=s+1; for(int i=0;i!=N;i++) cap[i][i+N]=1; for(int i=0;i!=F;i++) cap[s][i+2*N]=1; for(int i=0;i!=D;i++) cap[i+2*N+F][t]=1; for(int i=0;i!=N;i++) { scanf("%d%d",&f,&d); for(int j=0;j!=f;j++) { scanf("%d",&n); cap[2*N+n-1][i]=1; } for(int j=0;j!=d;j++) { scanf("%d",&n); cap[i+N][2*N+n+F-1]=1; } } cout<<GetMaxFlow(s,t,s+2,cap,flow)<<endl; }
下面是SAP的邻接表版本:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #define CLR(arr, val) memset(arr, val, sizeof(arr)) using namespace std; const int MAX=410,MAXE=40100*2,INF=100000000; inline int rev(int n) { return n+1 - 2* (n&1); } struct Graph { public: Graph():top(0) { CLR(head,-1); CLR(next,-1); } void Add(int u,int v,int c) { cap[top]=c; num[top]=v; next[top]=head[u]; head[u]=top; ++top; cap[top]=0; num[top]=u; next[top]=head[v]; head[v]=top; ++top; } int head[MAX]; int next[MAXE]; int num[MAXE]; int cap[MAXE]; int flow[MAXE]; private: int top; }; class SapMaxFlow { public: int GetMaxFlow(int s,int t,int v) { init(t, v); int total_flow = 0, cur = s; CLR(low,0); while(h[s] < v) { low[s] = INF; int i; for(i = g1.head[cur]; i != -1; i = g1.next[i]) { int u = g1.num[i], c = g1.cap[i], f = g1.flow[i]; if (c - f > 0 && h[cur] == h[u] + 1) { low[u] = min(low[cur],c - f); pre[u] = cur; pre_edge[u] = i; cur = u; if( cur == t) { total_flow += low[t]; while(cur != s) { g1.flow[pre_edge[cur]] += low[t]; g1.flow[rev(pre_edge[cur])] -= low[t]; cur=pre[cur]; } CLR(low,0); } break; } } if(i==-1) { int minh=INF; for(int i=g1.head[cur];i!=-1;i=g1.next[i]) if(g1.cap[i] - g1.flow[i] > 0 && h[g1.num[i]]+1<minh) minh = h[g1.num[i]]+1; h[cur] = minh; cur = s; } } return total_flow; } Graph g1,g2; private: int h[MAX],q[MAX],low[MAX],pre[MAX],pre_edge[MAX]; void init(int t,int v) { int head = 0,tail = 0; q[++tail]=t; h[t]=0; while(head < tail) { int cur=q[++head]; for(int i=g2.head[cur];i!=-1;i=g2.next[i]) { int u=g2.num[i],c=g2.cap[i]; if(!h[u] && c>0) { h[u]=h[cur]+1; q[++tail]=u; } } } } }; SapMaxFlow g; int main() { //freopen("in.txt","r",stdin); int N,F,D,f,d,n; scanf("%d%d%d",&N,&F,&D); int s=2*N+F+D,t=s+1; for(int i=0;i!=N;i++) { g.g1.Add(i,i+N,1); g.g2.Add(i+N,i,1); } for(int i=0;i!=F;i++) { g.g1.Add(s,i+2*N,1); g.g2.Add(i+2*N,s,1); } for(int i=0;i!=D;i++) { g.g1.Add(i+2*N+F,t,1); g.g2.Add(t,i+2*N+F,1); } for(int i=0;i!=N;i++) { scanf("%d%d",&f,&d); for(int j=0;j!=f;j++) { scanf("%d",&n); g.g1.Add(2*N+n-1,i,1); g.g2.Add(i,2*N+n-1,1); } for(int j=0;j!=d;j++) { scanf("%d",&n); g.g1.Add(i+N,2*N+n+F-1,1); g.g2.Add(2*N+n+F-1,i+N,1); } } cout<<g.GetMaxFlow(s,t,s+2)<<endl; }
相关文章推荐
- poj3281-Dining ,最大流量,内置图
- poj3281 Dining 最大流
- POJ3281 Dining 最大流
- poj3281 Dining 最大流
- POJ3281 Dining 求最大流
- 【poj3281】Dining 最大流
- 【poj3281】【最大流】Dining
- POJ3281 Dining (拆点+最大流)
- POJ3281 Dining(拆点构图 + 最大流)
- (拆点+最大流)POJ3281 Dining
- POJ3281 Dining 最大流 邻接表[模板]
- poj3281 Dining(最大流)
- POJ3281 Dining 最大流
- 【POJ3281】Dining【最大流】
- POJ3281 Dining(最大流+拆点)
- POJ3281 Dining [最大流应用]
- poj3281 Dining[最大流]
- POJ3281 Dining,最大流EK算法
- POJ3281 dining——最大流(建图是重点)
- poj3281 dining 网络流最大流算法