一.洛谷网络流24题(部分)
洛谷这些题都有很好的题解,这里就不再赘述了(懒)..
飞行员配对方案问题
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=101;
int n,m,next[20010],head[110],to[20010],las[20010],deep[110],num=-1;
void add_edge(int u,int v,int w)
{
next[++num]=head[u],
to[num]=v,las[num]=w,
head[u]=num;
}
bool bfs()
{
memset(deep,0,sizeof deep);
deep[s]=1;queue<int>q;
q.push(s);int nw;
while(!q.empty())
{
nw=q.front(),q.pop();
for(int i=head[nw];i!=-1;i=next[i])
if(las[i]&&!deep[to[i]])deep[to[i]]=deep[nw]+1,q.push(to[i]);
}
return deep[t];
}
int dfs(int pos,int flow)
{
if(pos==t)return flow;
for(int i=head[pos];i!=-1;i=next[i])
{
if(las[i]&&deep[to[i]]==deep[pos]+1)
{
int nw=dfs(to[i],min(flow,las[i]));
if(nw)
{
las[i]-=nw;las[i^1]+=nw;
return nw;
}
}
}
return 0;
}
void dinic()
{
int ans=0,tmp;
while(bfs())
{
while(tmp=dfs(s,1e9))
ans+=tmp;
}
printf("%d\n",ans);
for(int i=1;i<=m;i++)
for(int j=head[i];j!=-1;j=next[j])
{
if(!las[j]&&to[j]!=s){
printf("%d %d\n",i,to[j]);
break;
}
}
}
int main()
{
int i=0,j=0;
scanf("%d%d",&m,&n);
memset(head,-1,sizeof head),
memset(next,-1,sizeof next);
for(int i=1;i<=m;i++)
add_edge(s,i,1),add_edge(i,s,0);
for(int i=m+1;i<=n;i++)
add_edge(i,t,1),add_edge(t,i,0);
while(~scanf("%d%d",&i,&j))
{
if(i==-1&&j==-1)break;
if(i>j)swap(i,j);
add_edge(i,j,1),add_edge(j,i,0);
}
dinic();
}
方格取数问题
#include<bits/stdc++.h>
using namespace std;
int hd[10010],nxt[200010],las[200010],to[200010],num=-1,cur[10010],deep[10010],sum=0;
const int s=0,t=10005;
void add_edge(int u,int v,int w)
{
nxt[++num]=hd[u],to[num]=v,
las[num]=w,hd[u]=num;
}
void add(int u,int v,int w)
{add_edge(u,v,w),add_edge(v,u,0);}
bool bfs()
{
memset(deep,0,sizeof deep);
int nw;queue<int>q;
q.push(s);deep[s]=1;
while(!q.empty())
{
nw=q.front(),q.pop();
for(int i=hd[nw];i!=-1;i=nxt[i])
{
if(las[i]>0&&!deep[to[i]])
{
deep[to[i]]=deep[nw]+1;
q.push(to[i]);
}
}
}
return deep[t];
}
int dfs(int pos,int flow)
{
if(pos==t)return flow;
int nw;
for(int &i=cur[pos];i!=-1;i=nxt[i])
{
if(las[i]>0&&deep[to[i]]==deep[pos]+1)
{
nw=dfs(to[i],min(flow,las[i]));
if(nw>0)
{
las[i]-=nw;
las[i^1]+=nw;
return nw;
}
}
}
return 0;
}
void dinic()
{
int tmp,ans=0;
while(bfs())
{
for(int i=s;i<=t;i++)cur[i]=hd[i];
while(tmp=dfs(s,2e9))ans+=tmp;
}
printf("%d",sum-ans);
}
int main()
{
int n,m,tmp;
memset(nxt,-1,sizeof nxt),
memset(hd,-1,sizeof hd);
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&tmp),sum+=tmp,(i+j)&1?add(s,(i-1)*n+j,tmp):add((i-1)*n+j,t,tmp);
if((i+j)&1)
{
if(i>1)add((i-1)*n+j,(i-2)*n+j,2e9);if(i<m)add((i-1)*n+j,i*n+j,2e9);if(j>1)add((i-1)*n+j,(i-1)*n+j-1,2e9);if(j<n)add((i-1)*n+j,(i-1)*n+j+1,2e9);
}
}
}
dinic();
}
圆桌问题
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=500;
int m,n,sum=0,to[100010],hd[510],nxt[100010],las[100010],num=-1,deep[510],cur[510];
void add_edge(int u,int v,int w)
{
nxt[++num]=hd[u],las[num]=w,
to[num]=v,hd[u]=num;
}
void add(int u,int v,int w)
{
add_edge(u,v,w),
add_edge(v,u,0);
}
bool bfs()
{
memset(deep,0,sizeof deep);
queue<int>q;int nw;
deep[s]=1;q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop();
for(int i=hd[nw];i!=-1;i=nxt[i])
{
if(las[i]>0&&!deep[to[i]])deep[to[i]]=deep[nw]+1,q.push(to[i]);
}
}
return deep[t];
}
int dfs(int pos,int flow)
{
if(pos==t)return flow;
int nw;
for(int &i=cur[pos];i!=-1;i=nxt[i])
{
if(las[i]>0&&deep[to[i]]==deep[pos]+1)
{
nw=dfs(to[i],min(flow,las[i]));
if(nw>0)
{
las[i]-=nw;
las[i^1]+=nw;
return nw;
}
}
}
return 0;
}
void dinic()
{
int flow=0;
while(bfs())
{
for(int i=0;i<=500;i++)cur[i]=hd[i];
while(int tmp=dfs(s,1e9))flow+=tmp;
}
if(flow==sum)
{
printf("1\n");
for(int i=1;i<=m;i++)
{
for(int j=hd[i];j!=-1;j=nxt[j])
{
if(to[j]!=s&&las[j]==0)
{
printf("%d ",to[j]-m);
}
}
puts("");
}
}
else printf("0\n");
}
int main()
{
int tp;
memset(hd,-1,sizeof hd),
memset(nxt,-1,sizeof nxt);
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
add(i,m+j,1);
for(int i=1;i<=m;i++)
scanf("%d",&tp),sum+=tp,add(s,i,tp);
for(int i=1;i<=n;i++)
scanf("%d",&tp),add(i+m,t,tp);
dinic();
}
骑士共存问题
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=40005;
const int dx[]={2,2,1,1,-1,-1,-2,-2};
const int dy[]={1,-1,2,-2,2,-2,1,-1};
bool vis[210][210];
int m,n,hd[40010],nxt[1000010],las[1000010],to[1000010],num=-1,cur[40010],deep[40010];
inline void add_edge(int u,int v,int w)
{
nxt[++num]=hd[u],las[num]=w,
to[num]=v,hd[u]=num;
}
inline void add(int u,int v,int w)
{add_edge(u,v,w),add_edge(v,u,0);}
inline int get(int i,int j)
{return (i-1)*n+j;}
inline bool bfs()
{
memset(deep,0,sizeof deep);
queue<int>q;int nw;
deep[s]=1;q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop();
for(int i=hd[nw];i!=-1;i=nxt[i])
if(!deep[to[i]]&&las[i]>0)deep[to[i]]=deep[nw]+1,q.push(to[i]);
}
return deep[t];
}
inline int dfs(int pos,int flow)
{
if(pos==t)return flow;
for(register int &i=cur[pos];i!=-1;i=nxt[i])
{
if(deep[to[i]]==deep[pos]+1&&las[i])
{
int nw=dfs(to[i],min(las[i],flow));
if(nw>0)
{
las[i]-=nw,las[i^1]+=nw;
return nw;
}
}
}
return 0;
}
void dinic()
{
int flow=0,tmp;
while(bfs())
{
for(register int i=0;i<=t;i++)cur[i]=hd[i];
while(tmp=dfs(s,1e9))flow+=tmp;
}
cout<<n*n-m-flow;
}
int main()
{
int x,y,id,vx,vy;
memset(hd,-1,sizeof hd),
memset(nxt,-1,sizeof nxt);
scanf("%d%d",&n,&m);
for(register int i=1;i<=m;i++)
scanf("%d%d",&x,&y),vis[x][y]=1;
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
{
if(vis[i][j])continue;
id=get(i,j);
if((i+j)&1)add(s,id,1);else add(id,t,1);
if((i+j)&1)
for(register int k=0;k<8;k++)
{
vx=i+dx[k],vy=j+dy[k];
if(vx<1||vx>n||vy<1||vy>n||vis[vx][vy])continue;
add(id,get(vx,vy),1);
}
}
dinic();
}
分配问题
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=201;
int n,num=-1,hd[210],nxt[50010],to[50010],ww[50010],las[50010],cost[50010],dis[210],pre[210];bool inq[210];
void init()
{
memset(nxt,-1,sizeof nxt);
memset(hd,-1,sizeof hd);
}
void add_edge(int u,int v,int w,int c)
{
nxt[++num]=hd[u],to[num]=v,cost[num]=c,
las[num]=ww[num]=w,hd[u]=num;
}
bool spfa()
{
queue<int>q;int nw;
memset(inq,0,sizeof inq),
memset(dis,127,sizeof dis),
memset(pre,-1,sizeof pre);
dis[s]=0,inq[s]=1,q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop(),inq[nw]=0;
for(int i=hd[nw];i!=-1;i=nxt[i])
{
if(las[i]>0&&dis[to[i]]>dis[nw]+cost[i])
{
dis[to[i]]=dis[nw]+cost[i],pre[to[i]]=i;
if(!inq[to[i]])q.push(to[i]);inq[to[i]]=1;
}
}
}
return dis[t]<=2e9;
}
void mcmf(int op)
{
int flow,mnc=0;
while(spfa())
{
flow=1e9;
for(int i=pre[t];i!=-1;i=pre[to[i^1]])flow=min(flow,las[i]);
for(int i=pre[t];i!=-1;i=pre[to[i^1]])las[i]-=flow,las[i^1]+=flow;
mnc+=flow*dis[t];
}
printf("%d\n",mnc*op);
}
int main()
{
int tmp;init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
add_edge(s,i,1,0),add_edge(i,s,0,0);
for(int i=n+1;i<=2*n;i++)
add_edge(i,t,1,0),add_edge(t,i,0,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
scanf("%d",&tmp),add_edge(i,n+j,1,tmp),add_edge(n+j,i,0,-tmp);
}
mcmf(1);
for(int i=0;i<=num;i++)las[i]=ww[i],cost[i]=-cost[i];
mcmf(-1);
}
运输问题
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=201;
int hd[210],nxt[50010],to[50010],ww[50010],las[50010],cost[50010],num=-1,pre[210],dis[210];bool inq[210];
void add_edge(int u,int v,int w,int c)
{
nxt[++num]=hd[u],to[num]=v,cost[num]=c,
ww[num]=las[num]=w,hd[u]=num;
}
bool spfa()
{
memset(dis,127,sizeof dis),
memset(inq,0,sizeof inq),
memset(pre,-1,sizeof pre);
queue<int>q;int nw;
dis[s]=0,inq[s]=1,q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop(),inq[nw]=0;
for(int i=hd[nw];i!=-1;i=nxt[i])
{
if(las[i]>0&&dis[to[i]]>dis[nw]+cost[i])
{
dis[to[i]]=dis[nw]+cost[i],pre[to[i]]=i;
if(!inq[to[i]])q.push(to[i]);inq[to[i]]=1;
}
}
}
return dis[t]<=1e9;
}
void mcmf()
{
int flow,mc=0;
while(spfa())
{
flow=1e9;
for(int i=pre[t];i!=-1;i=pre[to[i^1]])flow=min(flow,las[i]);
for(int i=pre[t];i!=-1;i=pre[to[i^1]])las[i]-=flow,las[i^1]+=flow;
mc+=dis[t]*flow;
}
printf("%d\n",abs(mc));
}
int main()
{
int m,n,tmp;
memset(nxt,-1,sizeof nxt),
memset(hd,-1,sizeof hd);
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
scanf("%d",&tmp),add_edge(s,i,tmp,0),add_edge(i,s,0,0);
for(int i=1;i<=n;i++)
scanf("%d",&tmp),add_edge(m+i,t,tmp,0),add_edge(t,m+i,0,0);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&tmp);
add_edge(i,j+m,1e9,tmp),add_edge(j+m,i,0,-tmp);
}
}
mcmf();
for(int i=0;i<=num;i++)las[i]=ww[i],cost[i]=-cost[i];
mcmf();
}
负载平衡问题
#include<bits/stdc++.h>
using namespace std;
const int s=0,t=1050;
int hd[1100],nxt[20100],to[20100],las[20100],cost[20100],num=-1,dis[1100],pre[1100];bool inq[1100];
void add_edge(int u,int v,int w,int c)
{
nxt[++num]=hd[u],to[num]=v,
las[num]=w,cost[num]=c,hd[u]=num;
}
bool spfa()
{
memset(dis,127,sizeof dis),
memset(pre,-1,sizeof pre),
memset(inq,0,sizeof inq);
queue<int>q;int nw;
dis[s]=0,inq[s]=1,q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop();inq[nw]=0;
for(int i=hd[nw];i!=-1;i=nxt[i])
{
if(las[i]>0&&dis[to[i]]>dis[nw]+cost[i])
{
dis[to[i]]=dis[nw]+cost[i];pre[to[i]]=i;
if(!inq[to[i]])q.push(to[i]);inq[to[i]]=1;
}
}
}
return dis[t]<=1e9;
}
void mcmf()
{
int mc=0,flow;
while(spfa())
{
flow=2e9;
for(int i=pre[t];i!=-1;i=pre[to[i^1]])flow=min(flow,las[i]);
for(int i=pre[t];i!=-1;i=pre[to[i^1]])las[i]-=flow,las[i^1]+=flow;
mc+=flow*dis[t];
}
printf("%d",mc);
return;
}
int main()
{
int n,sum=0,tmp;
memset(hd,-1,sizeof hd),
memset(nxt,-1,sizeof nxt);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&tmp),add_edge(s,i,tmp,0),add_edge(i,s,0,0),sum+=tmp;sum/=n;
for(int i=1;i<=n;i++)
{
add_edge(i,t,sum,0),add_edge(t,i,0,0);
if(i>1)add_edge(i,i-1,1e9,1),add_edge(i-1,i,0,-1);
if(i<n)add_edge(i,i+1,1e9,1),add_edge(i+1,i,0,-1);
}
add_edge(1,n,1e9,1),add_edge(n,1,0,-1),add_edge(n,1,1e9,1),add_edge(1,n,0,-1);
mcmf();
}
二.其他
POJ-3281 Dining
一道需要拆点的题…
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;//F 1~100 N 101~200-201~300 D 301~400
const int s=0,t=505;
int hd[510],nxt[100010],las[100010],to[100010],num=-1,cur[510],deep[510];
void add(int u,int v,int w)
{
nxt[++num]=hd[u],to[num]=v,las[num]=w,hd[u]=num,
nxt[++num]=hd[v],to[num]=u,las[num]=0,hd[v]=num;
}
bool bfs()
{
int nw;queue<int>q;
memset(deep,0,sizeof deep);
deep[s]=1,q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop();
for(int i=hd[nw];i!=-1;i=nxt[i])
if(las[i]>0&&!deep[to[i]])deep[to[i]]=deep[nw]+1,q.push(to[i]);
}
return deep[t];
}
int dfs(int pos,int flow)
{
if(pos==t)return flow;
int nw;
for(int &i=cur[pos];i!=-1;i=nxt[i])
{
if(las[i]>0&&deep[to[i]]==deep[pos]+1)
{
nw=dfs(to[i],min(flow,las[i]));
if(nw>0)
{
las[i]-=nw;
las[i^1]+=nw;
return nw;
}
}
}
return 0;
}
void dinic()
{
int nw,flow=0;
while(bfs())
{
for(int i=s;i<=t;i++)cur[i]=hd[i];
while(nw=dfs(s,1e9))flow+=nw;
}
cout<<flow;
}
int main()
{
int n,f,d,F,D,tmp;
memset(hd,-1,sizeof hd);
memset(nxt,-1,sizeof nxt);
scanf("%d%d%d",&n,&f,&d);
for(int i=1;i<=f;i++)
add(s,i,1);
for(int i=301;i<=300+d;i++)
add(i,t,1);
for(int i=101;i<=100+n;i++)
add(i,i+100,1);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&F,&D);
for(int j=1;j<=F;j++)
scanf("%d",&tmp),add(tmp,i+100,1);
for(int j=1;j<=D;j++)
scanf("%d",&tmp),add(i+200,tmp+300,1);
}
dinic();
}
XJOI-线段的权
看不出是网络流的网络流..
在平面上有N条平行于Y轴的线段,每条线段都有一个权值,每次可以找出的Y轴上投影互不重叠的若干线段,求M次后,找出的线段最大权值和为多少。
N<=1000;M<=100;1<=Y1
#include<bits/stdc++.h>
using namespace std;
const int N=5010,s=0,t=5005,inf=1e9+7;
int to[20010],head[N+10],next[20010],las[20010],cost[20010],dis[20010],pre[N+10],num=-1;bool inq[N+10];
void add_edge(int u,int v,int w,int c)
{
next[++num]=head[u],
las[num]=w,to[num]=v,
cost[num]=c,head[u]=num;
}
void init()
{
memset(head,-1,sizeof head),
memset(next,-1,sizeof next);
for(int i=1;i<=N-1;i++)
add_edge(i,i+1,inf,0),add_edge(i+1,i,0,0);
return;
}
bool spfa()
{
memset(inq,0,sizeof inq),
memset(pre,-1,sizeof pre);
memset(dis,127,sizeof dis);
queue<int>q;int nw;
dis[s]=0,inq[s]=1;q.push(s);
while(!q.empty())
{
nw=q.front(),q.pop();inq[nw]=0;
for(int i=head[nw];i!=-1;i=next[i])
{
if(las[i]&&dis[to[i]]>dis[nw]+cost[i])
{
dis[to[i]]=dis[nw]+cost[i],pre[to[i]]=i;
if(!inq[to[i]])q.push(to[i]);inq[to[i]]=1;
}
}
}
return dis[t]<=1e9;
}
void mcmf()
{
int flow=0,nw=0,spd=0;
while(spfa())
{
nw=1e9;
for(int i=pre[t];i!=-1;i=pre[to[i^1]])nw=min(nw,las[i]);
for(int i=pre[t];i!=-1;i=pre[to[i^1]])las[i]-=nw,las[i^1]+=nw;
flow+=nw,spd+=nw*dis[t];
}
printf("%d",-spd);
}
int main()
{
int n,m,x,y1,y2,p;init();
scanf("%d%d",&n,&m);
add_edge(s,1,m,0),add_edge(1,s,0,0);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x,&y1,&y2,&p);
if(y1>y2)swap(y1,y2);
add_edge(y1,y2,1,-p),add_edge(y2,y1,0,p);
}
mcmf();
}