做比赛老是遇到网络流的题啊啊啊 开始搞起。。。
Ford标号法
poj 1149 PIGS
经典的构图题 一个人要卖猪 猪圈的钥匙在顾客手上 每个顾客有要买的猪的数量 求能卖出猪的最大数量
源点和每个猪圈的第一个顾客连边 边的权是猪圈中猪的数目 顾客跟汇点之间还有连边表示卖出猪的数目
做这种题构图真的很重要。。
代码如下。。。继续学习
<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;">#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define INF 0xfffffff
#define MAXN 1010
int s,t;//源点 汇点
int cust[MAXN][MAXN];// 节点之间的容量
int flow[MAXN][MAXN];//节点之间的流量
void init()//初始化 构造网络流
{
int M,N;//M是猪圈的数目 N是顾客的数目
int num;//顾客拥有的钥匙数目
int k;//第k个猪圈的钥匙
int house[MAXN];//存储每个猪圈中猪的数目
int last[MAXN];
memset(last,0,sizeof(last)); memset(cust,0,sizeof(cust));
scanf("%d%d",&M,&N);
s=0; t=N+1;
for(int i=1;i<=M;i++)//读入每个猪圈中猪的数目
scanf("%d",&house[i]);
for(int i=1;i<=N;i++)
{
scanf("%d",&num);
for(int j=0;j<num;j++)
{
scanf("%d",&k);//读入钥匙序号
if(last[k]==0)
cust[s][i]=cust[s][i]+house[k];
else //表示顾客i跟在顾客last[k]后面打开第k个猪圈
cust[last[k]][i]=INF;
last[k]=i;
}
scanf("%d",&cust[i][t]);//每个顾客到汇点的边 权值为顾客购买猪的数量
}
}
void ford()
{
//初始化为-2表示未标号 源点的标号为-1
int prev[MAXN];
int minflow[MAXN];
//广度优先搜索遍历网络
int que[MAXN];
int qs,qe;
int v;//当前检查的顶点
int p;
for(int i=0;i<MAXN;i++)
for(int j=0;j<MAXN;j++)
flow[i][j]=0;
minflow[0]=INF;//源点标号的第二个分量为无穷大
while(1)
{
for(int i=0;i<MAXN;i++)
prev[i]=-2;
prev[0]=-1;
qs=0; que[qs]=0; qe=1;
while(qs<qe&&prev[t]==-2)
{
v=que[qs]; qs++;
for(int i=0;i<t+1;i++)
{
// cust[v][i]-flow[v][i]!=0能保证顶点i是v的邻接顶点切能进行标号
if(prev[i]==-2&&(p=cust[v][i]-flow[v][i]))
{
prev[i]=v; que[qe]=i; qe++;
minflow[i]=(minflow[v]<p)?minflow[v]:p;
}
}
}
if(prev[t]==-2) break;
for(int i=prev[t],j=t;i!=-1;j=i,i=prev[i])
{
flow[i][j]+=minflow[t];
flow[j][i]=-flow[i][j];
}
}
p=0;
for(int i=0;i<t;i++)
{
p+=flow[i][t];
}
printf("%d\n",p);
}
int main()
{
freopen("ceshi.txt","r",stdin);
init();
ford();
return 0;
}
</span></span>
poj 1273 Drainage Ditches HDU1532
排水沟题 就是计算从源点到汇点最大的水流速度
建图相对比较简单 用增广路的方法求最大流
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 210
struct matrix
{
int c,f;
};
matrix Edge[MAXN][MAXN];//流及容量 邻接矩阵
int M,N; //排水沟即弧的数目 汇合节点即顶点的数目
int s,t;//源点 汇点
int residual[MAXN][MAXN]; //残留网络
int que[MAXN*MAXN],qs,qe;
int pre[MAXN];//前一个顶点的序号
int vis[MAXN];
int maxflow,min_augument;//最大流流量 每次增广时的可改进量
void find_augument_path()//BFS求增光路
{
int cu;
memset(vis,0,sizeof(vis));
qs=0; que[qs]=s;
pre[s]=s; vis[s]=1; qe=1;
memset(residual,0,sizeof(residual));
memset(pre,0,sizeof(pre));
while(qs<qe&&pre[t]==0)
{
cu=que[qs];
for(int i=1;i<=N;i++)
{
if(vis[i]==0)
{
if(Edge[cu][i].c-Edge[cu][i].f>0)
{
residual[cu][i]=Edge[cu][i].c-Edge[cu][i].f;
pre[i]=cu; que[qe++]=i; vis[i]=1;
}
else if(Edge[i][cu].f>0)//反向
{
residual[cu][i]=Edge[i][cu].f;
pre[i]=cu; que[qe++]=i; vis[i]=1;
}
}
}
qs++;
}
}
void augument_flow()//计算可改进量
{
int i=t;
if(pre[i]==0)
{
min_augument=0;
return;
}
int j=0xfffffff;
while(i!=s)//计算增光路上可改进量的最小值
{
if(residual[pre[i]][i]<j) j=residual[pre[i]][i];
i=pre[i];
}
min_augument=j;
}
void update_flow()//调整流量
{
int i=t;
if(pre[i]==0) return;
while(i!=s)
{
if(Edge[pre[i]][i].c-Edge[pre[i]][i].f>0) Edge[pre[i]][i].f+=min_augument;
else if(Edge[i][pre[i]].f>0) Edge[pre[i]][i].f+=min_augument;
i=pre[i];
}
}
void solve()
{
s=1; t=N;
maxflow=0;
while(1)
{
find_augument_path();
augument_flow();
maxflow+=min_augument;
if(min_augument>0) update_flow();
else return;
}
}
int main()
{
//freopen("ceshi.txt","r",stdin);
int u,v,c;
while(scanf("%d%d",&M,&N)!=EOF)
{
memset(Edge,0,sizeof(Edge));
for(int i=0;i<M;i++)
{
scanf("%d%d%d",&u,&v,&c);
Edge[u][v].c+=c;//可能会有重边
}
solve();
printf("%d\n",maxflow);
}
return 0;
}
poj 2112 Optimal Milking
最优的挤奶牛方案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX 300
#define INF 10000000
int dis[MAX][MAX];//任意连点间的最短路径
int map[MAX][MAX];//容量网络
bool sigh[MAX][MAX];//层次网络
bool used[MAX];
int K,C,n,M;
void Build_Graph(int min_max)//构建容量网络
{
memset(map,0,sizeof(map));
for(int i=K+1;i<=n;i++) map[0][i]=1;
for(int i=1;i<=K;i++) map[i][n+1]=M;
for(int i=K+1;i<=n;i++)
{
for(int j=1;j<=K;j++)
{
if(dis[i][j]<=min_max) map[i][j]=1;
}
}
}
bool BFS()//BFS构造层次网络
{
memset(used,0,sizeof(used));
memset(sigh,0,sizeof(sigh));
int que[100*MAX]={0};
que[0]=0;
used[0]=1;
int t=1,f=0;
while(f<t)
{
for(int i=0;i<=n+1;i++)
{
if(!used[i]&&map[que[f]][i])
{
que[t++]=i;
used[i]=1;
sigh[que[f]][i]=1;
}
}
f++;
}
if(used[n+1]) return true;
else return false;
}
int DFS(int v,int sum)
{
if(v==n+1) return sum;
int s=sum;
for(int i=0;i<=n+1;i++)
{
if(sigh[v][i])
{
int t=DFS(i,min(map[v][i],sum));
map[v][i]-=t;
map[i][v]+=t;
sum-=t;
}
}
return s-sum;
}
int main()
{
int L,R,mid,ans;
while(scanf("%d%d%d",&K,&C,&M)!=EOF)
{
n=K+C;
//Floyd算法 求任意两点间的最短距离
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&dis[i][j]);
if(dis[i][j]==0) dis[i][j]=INF;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
{
if(dis[i][k]!=INF)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
}
}
}
L=0;R=10000;
//二分搜索
while(L<R)
{
mid=(L+R)/2;
ans=0;
//Dinic算法求最大流
Build_Graph(mid);//构建容量网络
while(BFS()) ans+=DFS(0,INF);
if(ans>=C) R=mid;
else L=mid+1;
}
printf("%d\n",R);
}
return 0;
}
//待续