一、.这么犀利的建图第一次见到,不解释。就用这个题写一下模板。
参考资料:http://imlazy.ycool.com/post.2059102.html
二、代码
1.(dinic+邻接表)
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
//注意数据和内存的越界!
//尤其是memset()上
#define N 1010
#define M 11000//double
#define INF 100000000
int idx[N],cnt[N];
struct Node{
int u,v,next;
int c;
};
struct Graph
{
Node E[M];
int first[N];
int _V,_E,src,dest;
int que[N],front,rear;
int d[N];
void init(int n){
_V=n,_E=0;
src=0;dest=_V-1;
memset(first,-1,4*_V);//!!!
}
void build(int house,int cust)
{
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)add(idx[loop],i,INF);
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)add(src,i,cap);
scanf("%d",&num);
add(i,dest,num);
}
}
void add(int u,int v,int c){
E[_E].u=u,E[_E].v=v,E[_E].c=c,E[_E].next=first[u],first[u]=_E,_E++;
E[_E].u=v,E[_E].v=u,E[_E].c=0,E[_E].next=first[v],first[v]=_E,_E++;//
}
bool bfs()
{
memset(d,-1,4*_V);//!!!
d[src]=0;
front=rear=0;
que[rear++]=src;
while(front!=rear){
int u=que[front++];
for(int e=first[u];e!=-1;e=E[e].next){
int v=E[e].v;
if(d[v]==-1&&E[e].c){
d[v]=d[u]+1;
que[rear++]=v;
}
if(d[dest]!=-1)return true;
}
}
return false;
}
int dfs(int u,int cap)
{
if(u==dest)return cap;
int rest=cap,aug;
for(int e=first[u];e!=-1&&rest;e=E[e].next){//
int v=E[e].v,c=E[e].c;
if(d[v]==d[u]+1&&c){
aug=dfs(v,rest>c?c:rest);
rest-=aug;
E[e].c-=aug;
E[e^1].c+=aug;
}
}
return cap-rest;
}
int dinic(){
int flow=0;
while(bfs())flow+=dfs(src,INF);
return flow;
}
void display(){
for(int i=0; i<_V; i++){
for(int e=first[i]; e!=-1; e=E[e].next){
int u=E[e].u,v=E[e].v;
int c=E[e].c;
cout<<u<<' '<<v<<' ';
printf("%d\n",c);
}
}
}
}net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.dinic());
return 0;
}
三、dinic+邻接阵
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define N 1010
#define INF 100000000
int idx[N];
int cnt[N];
struct Graph{
int map[N][N];
int _V,src,dest;
int que[N],front,rear;
int d[N];
void init(int n)
{
_V=n;
src=0;dest=_V-1;
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)map[i][j]=0;//!!
}
void build(int house,int cust)
{
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)map[idx[loop]][i]=INF;
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)
map[src][i]=cap;
scanf("%d",&num);
map[i][dest]=num;
}
}
bool bfs(){
memset(d,-1,4*_V);//!!!
d[src]=0;
front=rear=0;
que[rear++]=src;
while(front!=rear){
int u=que[front++];
for(int v=0;v<_V;v++){
if(d[v]==-1&&map[u][v]){
d[v]=d[u]+1;
que[rear++]=v;
}
if(d[dest]!=-1)return true;//
}
}
return false;
}
//函数的意义:求从u增广的最大流量,cp:当前可增广的最大流
int dfs(int u,int cap){
if(u==dest)return cap;
int rest=cap,aug;
for(int v=0;v<_V&&rest;v++){
if(d[v]==d[u]+1&&map[u][v]>0){
aug=dfs(v,rest<map[u][v]?rest:map[u][v]);
rest-=aug;
map[u][v]-=aug;
map[v][u]+=aug;
}
}
return cap-rest;
}
int dinic(){
int flow=0;
while(bfs())flow+=dfs(src,INF);
return flow;
}
void display()
{
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)cout<<i<<' '<<j<<' '<<map[i][j]<<endl;
cout<<endl;
}
}net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.dinic());
return 0;
}
四、sap(邻接表)
一直都觉得从后往前标记不习惯,于是打算打算写从前往后标记的,但后来发现行不通!
才明白从后往前标记是没办法的办法呀!
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
//注意数据和内存的越界!
//尤其是memset()上
#define N 1010
#define M 11000//double
#define INF 100000000
int idx[N],cnt[N];
struct Node{
int u,v,next;
int c;
};
struct Graph
{
Node E[M];
int first[N];
int _V,_E,src,dest;
int d[N];
int num[N];
int pre[N],cur,next;
void init(int n){
_V=n,_E=0;
src=0;dest=_V-1;
memset(first,-1,4*_V);//!!!
}
void build(int house,int cust)
{
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)add(idx[loop],i,INF);
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)add(src,i,cap);
scanf("%d",&num);
add(i,dest,num);
}
}
void add(int u,int v,int c){
E[_E].u=u,E[_E].v=v,E[_E].c=c,E[_E].next=first[u],first[u]=_E,_E++;
E[_E].u=v,E[_E].v=u,E[_E].c=0,E[_E].next=first[v],first[v]=_E,_E++;//
}
inline bool advance(){
for(int e=first[cur];e!=-1;e=E[e].next){
if(d[cur]==d[E[e].v]+1&&E[e].c){
pre[cur=E[e].v]=e;
return true;
}
}
return false;
}
inline int relable(){
int mini=_V-1;
for(int e=first[cur];e!=-1;e=E[e].next)if(E[e].c&&d[E[e].v]<mini)mini=d[E[e].v];
return mini+1;
}
int sap(){
memset(d,-1,4*_V);//!!!
memset(num,0,4*_V);//
pre[src]=-1;//!!!
int flow=0,aug;
while(d[src]!=_V){
cur=src;
while(cur!=dest){
if(advance())continue;
int lable=relable();
num[d[cur]]--;num[d[cur]=lable]++;
if( !num[d[cur]] || d[src]==_V )return flow;
if(cur!=src)cur=E[pre[cur]].u;//满足可行弧定义
}
aug=INF;
int e=pre[dest],aug=INF;
while(e!=-1)aug=aug<E[e].c?aug:E[e].c,e=pre[E[e].u];
flow+=aug;e=pre[dest];
while(e!=-1)E[e].c-=aug,E[e^1].c+=aug,e=pre[E[e].u];
}
return flow;
}
}net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.sap());
return 0;
}
4.sap+邻接阵
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define N 1010
#define INF 100000000
int idx[N];
int cnt[N];
struct Graph{
int map[N][N];
int _V,src,dest;
int d[N];
int num[N];
int pre[N];
void init(int n){
_V=n;
src=0;dest=_V-1;
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)map[i][j]=0;//!!
}
void build(int house,int cust)
{
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)map[idx[loop]][i]=INF;
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)
map[src][i]=cap;
scanf("%d",&num);
map[i][dest]=num;
}
}
inline bool advance(int &u){
for(int v=0;v<_V;v++){
if(d[u]==d[v]+1&&map[u][v]){
pre[v]=u;u=v;
return true;
}
}
return false;
}
inline int relable(int u){
int mini=_V-1;
for(int v=0;v<_V;v++)
if(map[u][v]&&d[v]<mini)
mini=d[v];
return mini+1;
}
int sap(){
int u,v,flow=0;
memset(d,-1,4*_V);//bfs();
memset(num,0,4*_V);pre[src]=-1;
while(true){
u=src;
while(u!=dest){
if(advance(u))continue;
int lable=relable(u);
num[d[u]]--;num[d[u]=lable]++;
if( !num[d[u]] || d[src]==_V )return flow;
//!!源点标号不成功时,断层时到达最大流
if(u!=src)u=pre[u];
}
v=u,u=pre[v];int aug=INF;
while(u!=-1)aug=aug<map[u][v]?aug:map[u][v],v=u,u=pre[u];
flow+=aug;v=dest,u=pre[v];
while(u!=-1)map[u][v]-=aug,map[v][u]+=aug,v=u,u=pre[u];
}
return flow;
}
void display()
{
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)cout<<i<<' '<<j<<' '<<map[i][j]<<endl;
cout<<endl;
}
}net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.sap());
return 0;
}
我始终都没搞懂为什么sap用bfs()预处理就会WA,用memset(d,-1,4*_V)就不会!贴下bfs()的代码。。。
void bfs(){
memset(d,-1,4*_V);//!!!
num[d[dest]=0]++;
int que[N],front,rear;
front=rear=0;
que[rear++]=dest;
while(front!=rear){
int v=que[front++];
for(int u=0;u<_V;u++){
if(d[u]==-1&&map[u][v]){
num[d[u]=d[v]+1]++;
que[rear++]=u;
}
}
}
}
5.高标预流推进(邻接表)
#include<cstdio>
#include<iostream>
using namespace std;
// freopen("data.in","r",stdin);
#include<queue>
#include<cstring>
#define N 1010
#define M 11000//double
#define INF 100000000
int idx[N],cnt[N];
int d[N];
struct cmp{
bool operator()(const int &u,const int &v)const{
return d[u]<d[v];
}
};
struct Node{
int u,v,next;
int c;
};
struct Graph{
Node E[M];
int first[N];
int _V,_E,src,dest;
__int64 rest[N];
int in[N];
priority_queue<int,vector<int>,cmp> active;
void init(int n){
_V=n,_E=0;
src=0;dest=_V-1;
memset(first,-1,4*_V);//!!!
}
void build(int house,int cust){
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)add(idx[loop],i,INF);
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)add(src,i,cap);
scanf("%d",&num);
add(i,dest,num);
}
}
void add(int u,int v,int c){
E[_E].u=u,E[_E].v=v,E[_E].c=c,E[_E].next=first[u],first[u]=_E,_E++;
E[_E].u=v,E[_E].v=u,E[_E].c=0,E[_E].next=first[v],first[v]=_E,_E++;//
}
void calHeight(){
memset(d,-1,sizeof(d));
d[dest]=0;
int que[N],front,rear;
front=rear=0;
que[rear++]=dest;
while(front!=rear){
int v=que[front++],u;
for(int e=first[v]; e!=-1; e=E[e].next){
u=E[e].v;
if(d[u]==-1){
d[u]=d[v]+1;
que[rear++]=u;
}
}
}
}
void preprocess(){
for(int i=0;i<_V;i++)rest[i]=in[i]=0;
rest[src]=INF;active.push(src);
}
inline void push(int u){
for(int e=first[u]; e!=-1&&rest[u]; e=E[e].next){
int v=E[e].v,c=E[e].c;
if(d[E[e].v]+1==d[u]&&E[e].c){
int aug=rest[u]<c?rest[u]:c;//!!
rest[v]+=aug,rest[u]-=aug,E[e].c-=aug,E[e^1].c+=aug;
if(!in[v]&&v!=dest&&v!=src){
active.push(v);
in[v]=true;
}
}
}
}
inline bool relable(int u){
d[u]=_V-1;
for(int e=first[u]; e!=-1; e=E[e].next)if(E[e].c&&d[u]>d[E[e].v])d[u]=d[E[e].v];
d[u]++;
return d[u]!=_V;
}
__int64 preFlowPush(){
calHeight();
preprocess();
while(!active.empty()){//!!不记录s,t
int u=active.top();
push(u);//从点u进行推流
if(rest[u]&&relable(u))continue;//可以继续推流
active.pop();in[u]=false;//否则弹出队列
}
return rest[dest];
}
void display(){
for(int i=0; i<_V; i++){
for(int e=first[i]; e!=-1; e=E[e].next){
int u=E[e].u,v=E[e].v,c=E[e].c;
cout<<u<<' '<<v<<' '<<c<<endl;
}
}
}
} net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.preFlowPush());
return 0;
}
6.高标预流推进(邻接阵)
#include<cstdio>
#include<iostream>
using namespace std;
// freopen("data.in","r",stdin);
#include<queue>
#include<cstring>
#define N 1010
#define M 11000//double
#define INF 100000000
int d[N];
struct cmp{
bool operator()(const int &u,const int &v)const{
return d[u]<d[v];
}
};
int idx[N];
int cnt[N];
struct Graph{
int map[N][N];
int _V,_E,src,dest;
__int64 rest[N];
int in[N];
priority_queue<int,vector<int>,cmp> active;
void init(int n)
{
_V=n;
src=0;dest=_V-1;
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)map[i][j]=0;//!!
}
void build(int house,int cust)
{
init(cust+2);
int i,j;
for(i=1;i<=house;i++)
{
idx[i]=-1;
scanf("%d",cnt+i);
}
int loop,num,cap;
for(i=1;i<=cust;i++)
{
cap=0;
scanf("%d",&num);
for(j=0;j<num;j++)
{
scanf("%d",&loop);
if(idx[loop]!=-1)map[idx[loop]][i]=INF;
else cap+=cnt[loop],idx[loop]=i;
}
if(cap)
map[src][i]=cap;
scanf("%d",&num);
map[i][dest]=num;
}
}
void calHeight(){
memset(d,-1,sizeof(d));
d[dest]=0;
int que[N],front,rear;
front=rear=0;
que[rear++]=dest;
while(front!=rear){
int v=que[front++];
for(int u=0;u<_V;u++){
if(d[u]==-1){
d[u]=d[v]+1;
que[rear++]=u;
}
}
}
// d[src]=_V;//!!
}
void preprocess(){
for(int i=0;i<_V;i++)rest[i]=in[i]=0;
rest[src]=INF;active.push(src);
}
inline void push(int u){
for(int v=0;v<_V&&rest[u];v++){
if(d[v]+1==d[u]&&map[u][v]){
int aug=rest[u]<map[u][v]?rest[u]:map[u][v];//!!
rest[v]+=aug,rest[u]-=aug,map[u][v]-=aug,map[v][u]+=aug;
if(!in[v]&&v!=dest&&v!=src){
active.push(v);
in[v]=true;
}
}
}
}
inline bool relable(int u){
d[u]=_V-1;
for(int v=0;v<_V;v++)if(map[u][v]&&d[u]>d[v])d[u]=d[v];
d[u]++;
return d[u]!=_V;
}
__int64 preFlowPush(){
calHeight();
preprocess();
while(!active.empty()){//!!不记录s,t
int u=active.top();
push(u);//从点u进行推流
if(rest[u]&&relable(u))continue;//可以继续推流
active.pop();in[u]=false;//否则弹出队列
}
return rest[dest];
}
void display(){
for(int i=0;i<_V;i++)
for(int j=0;j<_V;j++)cout<<i<<' '<<j<<' '<<map[i][j]<<endl;
cout<<endl;
}
} net;
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n,m;
cin>>n>>m;
net.build(n,m);
// net.display();
printf("%d\n",net.preFlowPush());
return 0;
}