您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: