模板
using namespace std;
int n,m;
const int maxn=1005;
struct node
{
int to,next,cap;
}edge[maxn<<2];
int head[maxn],cnt;
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].next=head[u];
edge[cnt].cap=w; head[u]=cnt++;
}
int deep[maxn];
int bfs(int s,int t)
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==-1 && edge[i].cap>0)
{
deep[v]=deep[u]+1;
que.push(v);
}
}
}
return deep[t]!=-1;
}
int dfs(int u,int t,int maxflow)
{
if(u==t || maxflow==0) return maxflow;
int flow=0;
for(int i=head[u];i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==deep[u]+1 && edge[i].cap>0)
{
int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );
if(temp)
{
edge[i].cap -=temp;
edge[i^1].cap+=temp;
flow += temp;
if(maxflow==flow) break;
}
}
}
if(!flow) deep[u]=-1;
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
ans+=dfs(s,t,0x3f3f3f3f);
}
return ans;
}
POJ 1149
做法:建图是关键
建立超级起点汇点,每个顾客用一个点表示。
超级起点向每个猪圈第一个客人连猪圈的初始权值
每个猪圈的第I个客户向第I+1的客户连一条容量为inf 的边。
每个客户向超级汇点连一个容量为其最大购买容量的边!
POJ 1637
做法:存在欧拉回路的充要条件为每个点出入度相等,有向边无法改变方向对出入度影响是定值,重点在于无向边,初始时方向随意,若此时存在某点的出入度之差为奇数则不存在欧拉回路。设每个点出度-入度为x。 则该点的权值为x/2 。每改变一条相连的边出入度差值改变为2, 删除所有有向边,x/2>0与起点 连一条边,否则与汇点连一条边,如果最后满流这就说明了 存在欧拉回路
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int n,m;
const int maxn=3005;
struct node
{
int to,next,cap;
}edge[maxn<<2];
int head[maxn],cnt;
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].next=head[u];
edge[cnt].cap=w; head[u]=cnt++;
}
int deep[maxn];
int bfs(int s,int t)
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==-1 && edge[i].cap>0)
{
deep[v]=deep[u]+1;
que.push(v);
}
}
}
return deep[t]!=-1;
}
int dfs(int u,int t,int maxflow)
{
if(u==t || maxflow==0) return maxflow;
int flow=0;
for(int i=head[u];i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==deep[u]+1 && edge[i].cap>0)
{
int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );
if(temp)
{
edge[i].cap -=temp;
edge[i^1].cap+=temp;
flow += temp;
if(maxflow==flow) break;
}
}
}
if(!flow) deep[u]=-1;
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
ans+=dfs(s,t,0x3f3f3f3f);
}
return ans;
}
int in[maxn],out[maxn];
void init()
{
memset(head,-1,sizeof(head)); cnt=0;
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
in[b]++ ;out[a]++;
if(c==0)
{
add(a,b,1); add(b,a,0);
}
}
}
int work()
{
for(int i=1;i<=n;++i)
{
int temp=in[i]-out[i];
if( (temp%2+2)%2==1) return 0;
}
int sum=0;
for(int i=1;i<=n;++i)
{
int temp=out[i]-in[i];
if(temp>0)
{
add(0,i,temp/2); add(i,0,0);
}
else if(temp<0)
{
temp= -temp;
add(i,n+1,temp/2); add(n+1,i,0);sum+=(temp/2);
}
}
if(sum==dinic(0,n+1)) return 1;
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
if(work()) printf("possible\n");
else printf("impossible\n");
}
return 0;
}
POJ 2391
做法:二分时间 检验的时候将小于mid的边都加入,判断是否满流即可(要用floyd求出各个点之间的最短路)
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
typedef long long ll;
ll map[250][250];
int a[25000],b[25000],n,m,sum;
int s,t;
struct node
{
int to,next,cap;
}edge[200*200*10];
int head[250*10],cnt,deep[250*10];
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].next=head[u];
edge[cnt].cap=w; head[u]=cnt++;
}
int bfs(int s,int t)
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==-1 && edge[i].cap>0)
{
deep[v]=deep[u]+1;
que.push(v);
}
}
}
return deep[t]!=-1;
}
int dfs(int u,int t,int maxflow)
{
if(u==t || maxflow==0) return maxflow;
int flow=0;
for(int i=head[u];i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==deep[u]+1 && edge[i].cap>0)
{
int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );
if(temp)
{
edge[i].cap -=temp;
edge[i^1].cap+=temp;
flow += temp;
if(maxflow==flow) break;
}
}
}
if(!flow) deep[u]=-1;
return flow;
}
void gettu(ll mid)
{
s=0; t=2*n+1;
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=n;++i)
{
add(s,i,a[i]); add(i,s,0);
add(i+n,t,b[i]); add(t,i+n,0);
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if(map[i][j]<=mid)
{
add(i,j+n,0x3f3f3f3f);
add(j+n,i,0);
}
}
}
}
int dinic(ll mid)
{
gettu(mid);
int ans=0;
while(bfs(s,t))
{
ans+=dfs(s,t,0x3f3f3f3f);
}
if(ans==sum) return 1;
return 0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
sum=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
map[i][j]=1LL<<60;
}
map[i][i]=0;
}
for(int i=1;i<=n;++i)
{
scanf("%d%d",&a[i],&b[i]);
sum+=a[i];
}
for(int i=0;i<m;++i)
{
int x,y; ll w;
scanf("%d%d%lld",&x,&y,&w);
if(map[x][y]>w)
{
map[x][y]=map[y][x]=w;
}
}
ll maxn=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
for(int k=1;k<=n;++k)
{
map[j][k] = min(map[j][k],map[j][i]+map[i][k]);
if(map[j][k]!=(1LL<<60)) maxn=max(maxn,map[j][k]);
}
}
}
ll l=0,r=maxn+5, ans=-1,mid;
while(r>=l)
{
mid=(l+r)/2;
gettu(mid);
if(dinic(mid)) { r=mid-1; ans=mid; }
else l=mid+1;
}
printf("%lld\n",ans);
}
}
最小割:
Hoj:2634
做法:最大权闭合子图问题,答案为 all(权值)-最小割==最大流
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std;
int n,m;
const int maxn=10000;
struct node
{
int to,next,cap;
}edge[maxn<<2];
int head[maxn],cnt;
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].next=head[u];
edge[cnt].cap=w; head[u]=cnt++;
}
int deep[maxn];
int bfs(int s,int t)
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==-1 && edge[i].cap>0)
{
deep[v]=deep[u]+1;
que.push(v);
}
}
}
return deep[t]!=-1;
}
int dfs(int u,int t,int maxflow)
{
if(u==t || maxflow==0) return maxflow;
int flow=0;
for(int i=head[u];i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==deep[u]+1 && edge[i].cap>0)
{
int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );
if(temp)
{
edge[i].cap -=temp;
edge[i^1].cap+=temp;
flow += temp;
if(maxflow==flow) break;
}
}
}
if(!flow) deep[u]=-1;
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
ans+=dfs(s,t,0x3f3f3f3f);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&m,&n);
memset(head,-1,sizeof(head));
cnt=0;
int sum=0,a;
for(int i=1;i<=m;++i)
{
scanf("%d",&a);
add(0,i,a); add(i,0,0);
sum+=a;
}
for(int i=1;i<=n;++i)
{
scanf("%d",&a);
add(i+m,n+m+1,a); add(n+m+1,i+m,0);
}
for(int i=1;i<=m;++i)
{
int k;
scanf("%d",&k);
while(k--)
{
scanf("%d",&a);
add(i,a+m+1,0x3f3f3f3f);
add(a+m+1,i,0);
}
}
printf("%d\n",sum-dinic(0,n+m+1));
}
return 0;
}
Hoj2713
做法:二分图最大点权独立集;(如同黑白染色)
注意: 二分图最大点权独立集+二分图最小点权覆盖集==ALL
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <queue>
using namespace std;
int n,m,sum;
const int maxn=3000;
struct node
{
int to,next,cap;
}edge[1000001];
int head[maxn],cnt;
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].next=head[u];
edge[cnt].cap=w; head[u]=cnt++;
}
int deep[maxn];
int bfs(int s,int t)
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==-1 && edge[i].cap>0)
{
deep[v]=deep[u]+1;
que.push(v);
}
}
}
return deep[t]!=-1;
}
int dfs(int u,int t,int maxflow)
{
if(u==t || maxflow==0) return maxflow;
int flow=0;
for(int i=head[u];i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(deep[v]==deep[u]+1 && edge[i].cap>0)
{
int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) );
if(temp)
{
edge[i].cap -=temp;
edge[i^1].cap+=temp;
flow += temp;
if(maxflow==flow) break;
}
}
}
if(!flow) deep[u]=-1;
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
ans+=dfs(s,t,0x3f3f3f3f);
}
return ans;
}
int in[60][60];
int g[60][60];
int dir[4][2]= { {1,0} , {-1,0} , {0,-1} , {0,1} };
int id;
bool check(int x,int y)
{
if(x<=0||y<=0||x>n||y>m) return 0;
return 1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(in,0,sizeof(in));
id=0;
sum=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
++id;
scanf("%d",&g[i][j]);
in[i][j]=id;
sum+=g[i][j];
}
}
memset(head,-1,sizeof(head));
cnt=0;
int s=0,t=n*m+1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int id=in[i][j];
if((i+j)&1)
{
add(id,t,g[i][j]); add(t,id,0);
}
else
{
add(s,id,g[i][j]);
add(id,s,0);
for(int k=0;k<4;++k)
{
int x= i +dir[k][0];
int y= j +dir[k][1];
if(!check(x,y)) continue;
add(id,in[x][y],0x3f3f3f3f); add(in[x][y],id,0);
}
}
}
}
printf("%d\n",sum-dinic(s,t));
}
return 0;
}