入门看这个博客 https://blog.csdn.net/txl199106/article/details/64441994
但是这个博客里的模板比较基础,常数有点大,但是浅显易懂
下面这个模板比较快
#include
#include
#include
#include
#include
#define inf 1e8
using namespace std;
const int MAXN = 200;
const int MAXM = 51000;
const double eps = 1e-7;
const float EXP = exp(1.0);
int num, head[MAXN]; ///邻接表头结点
struct Edge {
int u, v, flow, nxt;
double cost;
Edge() {}
Edge(int u, int v, int flow, double cost, int nxt): u(u), v(v), flow(flow), cost(cost), nxt(nxt) {}
} E[MAXM];
int n, m;
void init() {
num = 0;
memset(head, -1, sizeof head);
}
void add(int u, int v, int flow, double cost) {
E[num] = Edge(u, v, flow, cost, head[u]);
head[u] = num++;
E[num] = Edge(v, u, 0, -cost, head[v]);
head[v] = num++;
}
int pre[MAXN], mi[MAXN];
double dis[MAXN];
bool vis[MAXN];
int s, t; ///源点汇点
double minCost;
int flow;
int que[MAXN];
bool SPFA() {
for(int i = 0; i <= t; i++)
vis[i] = 0, dis[i] = inf, pre[i] = -1;
dis[s] = 0, mi[s] = inf, vis[s] = true;
int l = 0, r = 1;
que[l] = s;
while(l != r) {
int u = que[l++];
if(l == MAXN) l = 0;
vis[u] = 0;
for(int i = head[u]; i + 1; i = E[i].nxt) {
int v = E[i].v;
if(E[i].flow > 0 && dis[v] > dis[u] + E[i].cost+eps) {
dis[v] = dis[u] + E[i].cost;
pre[v] = i;
mi[v] = min(mi[u], E[i].flow);
if(!vis[v]) {
vis[v] = 1;
que[r++] = v;
if(r >= MAXN) r -= MAXN;
}
}
}
}
if(pre[t] == -1) return false;
flow += mi[t];
minCost += mi[t] * dis[t];
int u = t;
for(int i = pre[u]; i + 1; i = pre[E[i].u]) {
E[i].flow -= mi[t];
E[i ^ 1].flow += mi[t];
}
return true;
}
double Mincost() {
minCost = 0, flow = 0;
while(SPFA());
return minCost;
}
int main() {
int T;
scanf("%d", &T);
while(T--){
init();
scanf("%d%d", &n, &m);
scanf("%d%d", &s, &t);
for(int i = 1; i <= m; i++){
int u, v, f;
double pp;
scanf("%d%d%d%lf", &u, &v, &f, &pp);
add(u, v, f, pp);
}
double tmp = Mincost();
printf("%.2f\n",tmp);
}
return 0;
}
2016ACM/ICPC亚洲区青岛站 G - Coding Contest
【题解】
如果S>B,从原点建一条边,如果B>S连向汇点建一条边
原题中的乘法取log换成加法,为了避免负值,所以取负值,但是单调性改变了,所以先用1-p,再取log
#include
#include
#include
#include
#include
#define inf 1e8
using namespace std;
const int MAXN = 200;
const int MAXM = 51000;
const double eps = 1e-7;
const float EXP = exp(1.0);
int num, head[MAXN]; ///邻接表头结点
struct Edge {
int u, v, flow, nxt;
double cost;
Edge() {}
Edge(int u, int v, int flow, double cost, int nxt): u(u), v(v), flow(flow), cost(cost), nxt(nxt) {}
} E[MAXM];
int n, m;
int S[MAXN],B[MAXN]; ///每个点的人数S,饭B
void init() {
num = 0;
memset(head, -1, sizeof head);
}
void add(int u, int v, int flow, double cost) {
E[num] = Edge(u, v, flow, cost, head[u]);
head[u] = num++;
E[num] = Edge(v, u, 0, -cost, head[v]);
head[v] = num++;
}
int pre[MAXN], mi[MAXN];
double dis[MAXN];
bool vis[MAXN];
int s, t; ///源点汇点
double minCost;
int flow;
int que[MAXN];
bool SPFA() {
for(int i = 0; i <= t; i++)
vis[i] = 0, dis[i] = inf, pre[i] = -1;
dis[s] = 0, mi[s] = inf, vis[s] = true;
int l = 0, r = 1;
que[l] = s;
while(l != r) {
int u = que[l++];
if(l == MAXN) l = 0;
vis[u] = 0;
for(int i = head[u]; i + 1; i = E[i].nxt) {
int v = E[i].v;
if(E[i].flow > 0 && dis[v] > dis[u] + E[i].cost+eps) {
dis[v] = dis[u] + E[i].cost;
pre[v] = i;
mi[v] = min(mi[u], E[i].flow);
if(!vis[v]) {
vis[v] = 1;
que[r++] = v;
if(r >= MAXN) r -= MAXN;
}
}
}
}
if(pre[t] == -1) return false;
flow += mi[t];
minCost += mi[t] * dis[t];
int u = t;
for(int i = pre[u]; i + 1; i = pre[E[i].u]) {
E[i].flow -= mi[t];
E[i ^ 1].flow += mi[t];
}
return true;
}
double Mincost() {
minCost = 0, flow = 0;
while(SPFA());
return minCost;
}
int main() {
int T;
scanf("%d", &T);
while(T--){
init();
scanf("%d%d", &n, &m);
s = 105, t = 106;
for(int i = 1; i <= n; i++){
scanf("%d%d", &S[i], &B[i]);
if(S[i] > B[i]){ ///人数大于饭数,源点建边出来
add(s, i, S[i] - B[i], 0);
}
if(B[i] > S[i]){ ///人数小于饭数,建边到汇点
add(i , t, B[i] - S[i], 0);
}
}
for(int i = 1; i <= m; i++){
int u, v, f;
double pp;
scanf("%d%d%d%lf", &u, &v, &f, &pp);
add(u, v, 1, 0); ///第一次走没有费用
add(u, v, f - 1, -log(1 - pp)); ///流量-1
}
double tmp = Mincost();
printf("%.2f\n",1 - exp(-tmp));
}
return 0;
}