1.AcWing382 k方格取数 最大费用流模版
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <math.h>
using namespace std;
#define INF 0x3f3f3f3f
#define num(i, j, k) ((i - 1) * n + j + k * n * n)
int n , k, tot = 0;
const int N = 55;
struct e
{
int t;
int c;
int w;
int next;
}edge[N*N*N];
int head[N*N*N] , h[N*N*N], dis[N*N*N], pre[N*N*N], pc[N*N*N], st, ed;
int ansflow , anscost, cnt;
void add(int f, int t, int c, int w)
{
edge[cnt].t = t;
edge[cnt].c = c;
edge[cnt].next = head[f];
edge[cnt].w = w;
head[f] = cnt ++;
edge[cnt].t = f;
edge[cnt].c = 0;
edge[cnt].next = head[t];
edge[cnt].w = -w;
head[t] = cnt ++;
}
struct node{
int v, val;
node(int a, int b):v(a), val(b){}
bool operator < (const node& no) const{
// return val > no.val; //最小费用
return val < no.val; //最大费用
}
};
void dij()
{
priority_queue < node > q;
while(true) //从汇点出发,不断寻找花费最短路作为增广路
{
for ( int i = 0 ; i <= ed ; i ++)
dis[i] = -999999999;
dis[st] = 0;
pre[st] = -1;
pc[st] = INF; //用于记录该增广路所能承受的最大流
q.push(node(st,0));
while(!q.empty()) //采用堆优化的dij寻找
{
node p = q.top();
q.pop();
int u = p.v;
if(p.val < dis[u]) continue;
for(int i = head[u] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].t , c = edge[i].c, w = edge[i].w;
int ww = w + h[u] - h[v]; //引入势函数作为新权,保证正数,从而让成功,类似于Johnson算法
if(c > 0 && dis[u] + ww > dis[v])
{
dis[v] = dis[u] + ww; //修改距离
q.push(node(v,dis[v]));
pre[v] = i; //记录路径
pc[v] = min(pc[u],c); //修改最大流
}
}
}
if(dis[ed] == -999999999) //如果为INF说明不存在增广路,跳出即可
break;
for(int i = 1 ; i <= ed ; i ++) h[i] += dis[i]; //更新势函数
// for(int i = 1 ; i <= ed ; i ++) {
// if(dis[i] > -999999999)
// h[i] += dis[i];
// }
int nowflow = pc[ed];
ansflow += nowflow;
anscost += h[ed]*nowflow;
for(int i = ed ; pre[i] != -1 ; i = edge[pre[i]^1].t) //递归回溯路径,改变流大小
{
edge[pre[i]].c -= nowflow;
edge[pre[i]^1].c += nowflow;
}
}
}
int main(void)
{
memset(head,-1,sizeof head);
scanf("%d%d", &n, &k);
st = num(1, 1, 0), ed = num(n, n, 1);
for (int i = 1; i <= n; i++) {
for (int j = 1, x; j <= n; j++) {
scanf("%d", &x);
add(num(i, j, 0), num(i, j, 1), 1, x);
add(num(i, j, 0), num(i, j, 1), k - 1, 0);
if (i + 1 <= n) add(num(i, j, 1), num(i + 1, j, 0), k, 0);
if (j + 1 <= n) add(num(i, j, 1), num(i, j + 1, 0), k, 0);
}
}
dij();
cout << anscost << endl;
}
luoguP3381 最小费用模版
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <math.h>
using namespace std;
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define num(i, j, k) ((i - 1) * n + j + k * n * n)
int n , m, tot = -1;
const int N = 55;
struct e
{
int t;
int c;
int w;
int next;
}edge[N*N*N];
int head[N*N*N] , h[N*N*N], dis[N*N*N], pre[N*N*N], pc[N*N*N], st, ed;
int ansflow , anscost, cnt = 1;
void add(int f, int t, int c, int w)
{
edge[++ cnt].t = t;
edge[cnt].c = c;
edge[cnt].next = head[f];
edge[cnt].w = w;
head[f] = cnt ;
edge[++ cnt].t = f;
edge[cnt].c = 0;
edge[cnt].next = head[t];
edge[cnt].w = -w;
head[t] = cnt ;
}
void dij()
{
priority_queue <pair<int,int> > q;
while(true) //从汇点出发,不断寻找花费最短路作为增广路
{
memset(dis,INF,sizeof(dis));
dis[st] = 0;
pre[st] = -1;
pc[st] = INF; //用于记录该增广路所能承受的最大流
q.push(make_pair(0,st));
while(!q.empty()) //采用堆优化的dij寻找
{
pair<int,int> p = q.top();
q.pop();
int u = p.se;
if(-p.fi > dis[u]) continue;
for(int i = head[u] ; i != -1; i = edge[i].next)
{
int v = edge[i].t , c = edge[i].c, w = edge[i].w;
int ww = w + h[u] - h[v]; //引入势函数作为新权,保证正数,从而让成功,类似于Johnson算法
if(c > 0 && dis[u] + ww < dis[v])
{
dis[v] = dis[u] + ww; //修改距离
q.push(make_pair(-dis[v],v));
pre[v] = i; //记录路径
pc[v] = min(pc[u],c); //修改最大流
}
}
}
if(dis[ed] == INF) //如果为INF说明不存在增广路,跳出即可
break;
for(int i = 1 ; i <= n ; i ++) {
if(dis[i] < INF)
h[i] += dis[i];
}
int nowflow = pc[ed];
ansflow += nowflow;
anscost += h[ed]*nowflow;
for(int i = ed ; pre[i] != -1 ; i = edge[pre[i]^1].t) //递归回溯路径,改变流大小
{
edge[pre[i]].c -= nowflow;
edge[pre[i]^1].c += nowflow;
}
}
}
int main(void)
{
memset (head, -1 , sizeof head);
scanf("%d %d %d %d", &n , &m ,&st, &ed);
for(int i = 1 ; i <= m ; i ++)
{
int u , v, c, w;
scanf("%d %d %d %d", &u , &v ,&c, &w);
add(u,v,c,w);
}
dij();
cout << ansflow << " "<< anscost << endl;
}