图论结论
1.任意一个有6个顶点的简单图或其补图一定包含一个三角形(Ramsey定理)
流函数三大性质:
1)容量限制:f(x,y) <= c(x,y)
2)斜对称:f(x,y)=-f(y,x)
3)流量守恒:x!=S,x!=T,Σf(u,x)=Σf(x,v)
c(x,y)=0说明该条边不在图中,同时f(x,y)<=0
最大流
EK算法 O(ve^2) 10^3--10^4 稀疏图
HDU 1532
using namespace std;
const int INF=0x7fffffff;
const int MAXN=250;
struct Edge{
int to,w,next;
}edge[MAXN<<1]; //边要开两倍啊
int head[MAXN];
int tot;
void add(int u,int v,int w)
{
edge[++tot].w+=w; //有重边所以是+
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot;
return ;
}
void init()
{
tot=1;
memset(head,-1,sizeof(head));
memset(edge,0,sizeof(edge));
}
int N,M,S,T;
int vis[MAXN];
struct Pre{
int u,e;
}pre[MAXN];
inline int bfs()
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
queue<int> q;
q.push(S); vis[S]=1;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(!vis[v]&&edge[i].w){
pre[v].u=u; pre[v].e=i;
if(v==T) return 1;
vis[v]=1; q.push(v);
}
}
}
return 0;
}
inline int EK()
{
int ans=0;
while(bfs()){
int mmin=INF;
for(int i=T;i!=S;i=pre[i].u){
mmin=min(mmin,edge[pre[i].e].w);
}
for(int i=T;i!=S;i=pre[i].u){
edge[pre[i].e].w-=mmin;
edge[pre[i].e^1].w+=mmin;
}
ans+=mmin;
}
return ans;
}
int main()
{
while(~scanf("%d%d",&M,&N)){
init();
S=1,T=N;
for(int i=1;i<=M;++i){
int u,v,w; scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,0);
}
printf("%d\n",EK());
}
return 0;
}
Dinic 算法 O(v^2e) 10^4--10^5 稠密图
求解二分图最大匹配的时间复杂度O(e sqrt(v))
using namespace std;
const int MAXN=2e4+1000;
const int INF=1e9;
struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
};
int N,M,S,T;
struct Dinic{
vector<Edge> edges;
vector<int> G[MAXN];
int vis[MAXN],d[MAXN],cur[MAXN]; //代表从这条边下去一定搜不到
void init()
{
for(int i=0;i<=N;++i) G[i].clear();
edges.clear();
}
void add(int u,int v,int w)
{
edges.push_back(Edge(u,v,w,0));
edges.push_back(Edge(v,u,0,0));
int si=edges.size();
G[u].push_back(si-2);
G[v].push_back(si-1);
}
int Bfs()//分层图
{
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
d[S]=0; vis[S]=1;
queue<int> Q;
Q.push(S);
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=0;i<G[u].size();++i){
Edge &tmp=edges[G[u][i]];
if(!vis[tmp.to]&&tmp.cap>tmp.flow){
vis[tmp.to]=1;
d[tmp.to]=d[u]+1;
Q.push(tmp.to);
}
}
}
return vis[T];
}
int Dfs(int node,int a)//a当前为止所有弧的最小残量
{
if(node==T||a==0) return a;
int flow=0,f;
for(int &i=cur[node];i<G[node].size();++i){//cur当前弧优化
Edge &tmp=edges[G[node][i]];
if(d[tmp.to]==d[node]+1&&(f=Dfs(tmp.to,min(a,tmp.cap-tmp.flow)))>0){
flow+=f;
tmp.flow+=f;
edges[G[node][i]^1].flow-=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int MaxFlow()
{
int flow=0;
while(Bfs()){
memset(cur,0,sizeof(cur));
flow+=Dfs(S,INF);
}
return flow;
}
};
Dinic dinic;
int main()
{
while(~scanf("%d%d",&M,&N)){
S=1,T=N;
dinic.init();
int u,v,w;
for(int i=1;i<=M;++i){
scanf("%d%d%d",&u,&v,&w);
dinic.add(u,v,w);
}
int ans=0;
ans=dinic.MaxFlow();
printf("%d\n",ans);
}
return 0;
}
ISAP算法 O(v^2E)
using namespace std;
const int MAXN=1e4+100;
const int INF=0x7fffffff;
struct Edge{
int from,to,cap,flow;
};
bool operator<(const Edge &a,const Edge &b){
return a.from<b.from||(a.from==b.from&&a.to<b.to);
}
int N,M,S,T;
struct ISAP{
vector<Edge> edges;
vector<int> G[MAXN];
int vis[MAXN],d[MAXN],cur[MAXN],p[MAXN],num[MAXN]; //p:增广路上的上一条弧 num:距离标号计数
void add(int u,int v,int w){
edges.push_back((Edge){u,v,w,0});
edges.push_back((Edge){v,u,0,0});
int si=edges.size();
G[u].push_back(si-2);
G[v].push_back(si-1);
}
int Bfs() //分层图
{
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
queue<int> Q;
Q.push(T); vis[T]=1;
while(!Q.empty()){
int v=Q.front(); Q.pop();
for(int i=0;i<G[v].size();++i){
Edge &e=edges[G[v][i]^1];
if(!vis[e.from]&&e.cap>e.flow){
vis[e.from]=1;
d[e.from]=d[v]+1;
Q.push(e.from);
}
}
}
return vis[S];
}
void init()
{
for(int i=0;i<=N;++i) G[i].clear();
edges.clear();
}
int Augment()
{
int x=T,a=INF;
while(x!=S){
Edge &e=edges[p[x]];
a=min(a,e.cap-e.flow);
x=edges[p[x]].from;
}
x=T;
while(x!=S){
edges[p[x]].flow+=a;
edges[p[x]^1].flow-=a;
x=edges[p[x]].from;
}
return a;
}
int MaxFlow()
{
Bfs();
memset(num,0,sizeof(num));
memset(cur,0,sizeof(cur));
int flow=0;
for(int i=0;i<=N;++i) num[d[i]]++;
int x=S;
while(d[S]<N){
if(x==T){
flow+=Augment();
x=S;
}
int ok=0;
for(int i=cur[x];i<G[x].size();++i){
Edge &e=edges[G[x][i]];
if(e.cap>e.flow&&d[x]==d[e.to]+1){
ok=1;
p[e.to]=G[x][i];
cur[x]=i;
x=e.to;
break;
}
}
if(!ok){
int m=N-1;
for(int i=0;i<G[x].size();++i){
Edge &e=edges[G[x][i]];
if(e.cap>e.flow) m=min(m,d[e.to]);
}
if(--num[d[x]]==0) break;
num[d[x]=m+1]++;
cur[x]=0;
if(x!=S) x=edges[p[x]].from;
}
}
return flow;
}
};
ISAP g;
int main()
{
while(~scanf("%d%d",&M,&N)){
g.init();
S=1,T=N;
int u,v,w;
for(int i=1;i<=M;++i){
scanf("%d%d%d",&u,&v,&w);
g.add(u,v,w);
}
printf("%d\n",g.MaxFlow());
}
return 0;
}
    向wjmzbmr学习,acm本就是逆天而行。
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号