很棒的最小割模型論文(手動置頂)
Dinic
interger型
#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}
const int maxn = 1e5+7;
const int maxm = 3e5+7;
const int inf = 0x3f3f3f3f;
int head[maxn], to[maxm], w[maxm], nxt[maxm], tot=1;
int cur[maxn], level[maxn];
void add_edge(int u, int v, int c) {
++tot; to[tot]=v; w[tot]=c; nxt[tot]=head[u]; head[u]=tot;
++tot; to[tot]=u; w[tot]=0; nxt[tot]=head[v]; head[v]=tot;
}
bool bfs(int s, int t) {
memset(level,0,sizeof(level));
queue<int> q;
level[s]=1;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
for(int i=head[u]; i; i=nxt[i]) {
int v=to[i];
if(!w[i]||level[v]) continue;
level[v]=level[u]+1;
q.push(v);
}
}
return level[t];
}
int dfs(int u, int t, int flow) {
if(u==t||flow==0) return flow;
int f, ret=0;
for(int &i=cur[u]; i; i=nxt[i]) {
int v=to[i];
if(level[v]==level[u]+1&&(f=dfs(v,t,min(flow,w[i])))>0) {
w[i]-=f; w[i^1]+=f;
flow-=f; ret+=f;
if(!flow)break;
}
}
if(!ret) level[u]=0;
return ret;
}
int dinic(int s, int t) {
int ret=0;
while(bfs(s,t)) memcpy(cur,head,sizeof(cur)), ret+=dfs(s,t,inf);
return ret;
}
int main() {
int n=read(), m=read(), s=read(), t=read();
for(int i=1; i<=m; ++i) {
int u=read(), v=read(), w=read();
add_edge(u,v,w);
}
printf("%d\n", dinic(s,t));
}
double型
#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}
const int maxn = 1e5+7;
const int maxm = 3e5+7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
int head[maxn], to[maxm], nxt[maxm], tot=1;
double w[maxm];
int cur[maxn], level[maxn];
void add_edge(int u, int v, double c) {
++tot; to[tot]=v; w[tot]=c; nxt[tot]=head[u]; head[u]=tot;
++tot; to[tot]=u; w[tot]=0; nxt[tot]=head[v]; head[v]=tot;
}
bool bfs(int s, int t) {
memset(level,0,sizeof(level));
queue<int> q;
level[s]=1;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
for(int i=head[u]; i; i=nxt[i]) {
int v=to[i];
if(fabs(w[i])<=eps||level[v]) continue;
level[v]=level[u]+1;
q.push(v);
}
}
return level[t];
}
double dfs(int u, int t, double flow) {
if(u==t||fabs(flow)==0) return flow;
double f, ret=0;
for(int &i=cur[u]; i; i=nxt[i]) {
int v=to[i];
if(level[v]==level[u]+1&&(f=dfs(v,t,min(flow,w[i])))>=eps) {
w[i]-=f; w[i^1]+=f;
flow-=f; ret+=f;
if(fabs(flow)<=eps)break;
}
}
if(fabs(ret)<=eps) level[u]=0;
return ret;
}
double dinic(int s, int t) {
double ret=0;
while(bfs(s,t)) memcpy(cur,head,sizeof(cur)), ret+=dfs(s,t,5e18);
return ret;
}
int main() {
int n=read(), m=read(), s=read(), t=read();
for(int i=1; i<=m; ++i) {
int u=read(), v=read();
double w; scanf("%lf", &w);
add_edge(u,v,w);
}
printf("%.3f\n", dinic(s,t));
}
費用流
#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}
const int maxn = 2e4+7;
const int maxm = 2e5+7;
const int inf = 0x3f3f3f3f;
ll maxflow, mincost;
int last[maxn], pre[maxn], dis[maxn], now[maxn];
int head[maxn], to[maxm], flow[maxm], cost[maxm], nxt[maxm], tot=1;
bool inq[maxn];
void add_edge(int u,int v,int f,int c) {
++tot; to[tot]=v; flow[tot]=f; cost[tot]=c; nxt[tot]=head[u]; head[u]=tot;
++tot; to[tot]=u; flow[tot]=0; cost[tot]=-c; nxt[tot]=head[v]; head[v]=tot;
}
void init() { tot=1; memset(head,0,sizeof(head)); mincost=maxflow=0; }
bool spfa(int s, int t) {
memset(dis,inf,sizeof(dis));
memset(now,inf,sizeof(now));
memset(inq,0,sizeof(inq));
queue<int> q;
dis[s]=0; pre[t]=-1; q.push(s); inq[s]=1;
while(!q.empty()) {
int u=q.front(); q.pop(); inq[u]=0;
for(int i=head[u]; i; i=nxt[i]) {
int v=to[i];
if(flow[i]>0&&dis[v]>dis[u]+cost[i]) {
dis[v]=dis[u]+cost[i];
now[v]=min(now[u],flow[i]);
last[v]=i; pre[v]=u;
if(!inq[v]) q.push(v), inq[v]=1;
}
}
}
return pre[t]!=-1;
}
void MCMF(int s, int t) {
while(spfa(s,t)) {
int u=t;
maxflow+=now[t];
mincost+=now[t]*ll(dis[t]);
while(u!=s) {
flow[last[u]]-=now[t];
flow[last[u]^1]+=now[t];
u=pre[u];
}
}
}
int main() {
int n=read(), m=read(), s=read(), t=read();
for(int i=1; i<=m; ++i) {
int u=read(), v=read(), w=read(), f=read();
add_edge(u,v,w,f);
}
MCMF(s,t);
printf("%lld %lld\n", maxflow, mincost);
}
最大權閉合子圖
閉合圖(針對有向圖):圖中點集的出邊也在點集中。(相當於有向邊終點是有向邊起點的必要條件)
最大權閉合子圖:圖中每個點有點權,則權值最大的閉合子圖爲最大權閉合子圖。
原閉合圖構造:額外加入源點 ,匯點 ,與 相連的點( )的點權都爲正,與 相連的點( )的點權都爲負(0就隨意啦),這兩者的邊權用點權(取絕對值)代替; 與 的連邊邊權爲無窮。
最大權閉合子圖權值爲:( 爲閉合圖的最小割 )
(由於 都是無窮邊,因此最小割一定是簡單割,即所有割邊都與源點或匯點相連)