输出格式:输出总愉悦值的最大值。
大致思路:
又是这种“对应匹配关系”,很容易让人联想到建图。这明显是一个最大费用的题,所以毋庸置疑肯定也是想要最大流的。
按照算法模板把spfa改成求(费用权)最长路即可。注意要修改两个地方:距离数组d的初始化要为-inf,用于更新的if语句<改成>。而且在算法模板里要注意,因为是while循环spfa,所以在spfa里要重新初始化visit数组和d数组和pre数组。
加深了对最小/大费用最大流的题的建图的理解——权值不是有两个吗,一个是c容量,一个是w费用权,那么结合题意,我们取的容量c一般是该物品的“数量”,取的费用权w一般是题中给的比如说时间啊价值啊什么的定义)”。这里的图中,左边排列点“贴纸”,右边排列点“玩偶”,左边从源点连线为贴纸数量,右边连线到汇点为玩偶数量,两边的费用权都为0,连接贴纸i和玩偶j的边中,容量可以设为inf(当然设为min(贴纸i数量,玩偶j数量)),费用权设为H(i,j)。
AC代码:
#include<iostream> #include<bits/stdc++.h> using namespace std; const int MAX_N = 1000; const int MAX_M = 10000; const int inf = 0x3f3f3f3f; struct edge { int v, c, w, next; // v 表示边的另一个顶点,c 表示当前剩余容量,w 表示单位流量费用 } e[MAX_M]; int p[MAX_N], s, t, eid; // s 表示源点,t 表示汇点,需要在进行 costflow 之前设置完毕 void init() { memset(p, -1, sizeof(p)); eid = 0; } void insert(int u, int v, int c, int w) { e[eid].v = v; e[eid].c = c; e[eid].w = w; e[eid].next = p[u]; p[u] = eid++; } void addedge(int u, int v, int c, int w) { insert(u, v, c, w); insert(v, u, 0, -w); } bool inq[MAX_N]; int d[MAX_N]; // 如果到顶点 i 的距离是 0x3f3f3f3f,则说明不存在源点到 i 的最短路 int pre[MAX_N]; // 最短路中连向当前顶点的边的编号 bool spfa() { // 以源点 s 为起点计算单源最短路,如果不存在从 s 到 t 的路径则返回 false,否则返回 true memset(inq, 0, sizeof(inq)); memset(d, -0x3f, sizeof(d)); memset(pre, -1, sizeof(pre)); d[s] = 0; inq[s] = true; queue<int> q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; for (int i = p[u]; i != -1; i = e[i].next) { if (e[i].c) { int v = e[i].v; if (d[u] + e[i].w > d[v]) { d[v] = d[u] + e[i].w; pre[v] = i; if (!inq[v]) { q.push(v); inq[v] = true; } } } } } return pre[t] != -1; } int costflow() { // 计算最小费用最大流 int ret = 0; // 累加和 while(spfa()) { int flow = inf; for(int i = t; i != s; i = e[pre[i]^1].v) { flow = min(e[pre[i]].c, flow); // 计算当前增广路上的最小流量 } for(int i = t; i != s; i = e[pre[i]^1].v) { e[pre[i]].c -= flow; e[pre[i]^1].c += flow; ret += e[pre[i]].w * flow; } } return ret; } int tiezhi[MAX_N]; int wanou[MAX_N]; int main() { init(); int m,n; cin>>m>>n; s=0; t=m+n+1; for(int i=1;i<=m;i++) { scanf("%d",&tiezhi[i]); addedge(s,i,tiezhi[i],0); } for(int i=1;i<=n;i++) { scanf("%d",&wanou[i]); addedge(m+i,t,wanou[i],0); } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { int h; scanf("%d",&h); addedge(i,m+j,0x3f3f3f3f,h); } } cout<<costflow(); return 0; }主函数最开始别忘了要先init()啊!!不然运行超时一脸懵逼!!!