一类特殊的模拟费用流模型
QOJ 7185
题目描述
有
思路点拨
看到这个题目很容易想到一个网络流建模:
-
一个源点,一个汇点,
个代表学生的节点, 个代表科目的节点。 -
学生节点向源点连流量为
,代价为 的边。 -
科目节点向汇点连流量为
,代价为 的边。 -
第
个同学向第 个科目练流量为 ,代价为 的边。
最终该网络的最小费用最大流就是正确答案。相比之下我们更加关心图的性质以及增广路的形态。
经过观察,图具有如下性质:
-
图是一张二分图,那么每一条增广路除了源点和汇点之外都是左-右-左交替的。
-
最短路本身的性质:不会经过相同的节点(该网络图不存在负环)。
-
关键性质:注意到结合上述两个性质,每一条增广路的长度都是
级别的,因为右部点的数量很少。
我们将一次增广路径画出来:

这条增广路有什么具体含义吗?
那么我们考虑将路径分为几个部分:
- 从源点到达第一个左部点,从左部点到达第一个右部点。
- 对于一个右部点,认为一次移动是"右-左-右"。
- 右部点经过若干次移动到达最后一个右部点,并走向汇点。
当然,这个路径的权值和需要尽可能的小。
先考虑如何维护出两个右部点
那么对于上述路径中的
接下来考虑维护第一部分。我们可以枚举第一个右部点
我们还存在一个问题,就是增广一条路径之后需要做出一些修改操作。具体而言就是部分节点(
单轮增广的时间复杂度是
一共增广
[AGC018C] Coins
题目描述
有
要选出
思路点拨
这个题目可以使用上述模型解决。
对于三个硬币,可以看作上述题目的三个科目。则第
三个硬币向汇点连流量分别为
因为本题
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e5+5,inf=1e18;
int A,B,C,n;
int a[MAXN][4];
struct heap{
priority_queue<pair<int,int>> q1,q2;
void push(pair<int,int> x){
q1.push(x);
}
void pop(pair<int,int> x){
q2.push(x);
}
pair<int,int> top(){
while(!q2.empty()&&q1.top()==q2.top())
q1.pop(),q2.pop();
if(q1.empty()) return make_pair(-inf,0);
return q1.top();
}
}q[4][4],p[4];
int e[5][5],dis[5],pre[5];
bool vis[5];
void SPFA(){
queue<int> q;
for(int i=1;i<=4;i++)
dis[i]=-inf,pre[i]=0;
dis[4]=0;
q.push(4);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=1;i<=4;i++){
if(dis[i]<dis[u]+e[i][u]){
dis[i]=dis[u]+e[i][u];
pre[i]=u;
if(!vis[i]){
vis[i]=1;
q.push(i);
}
}
}
}
}
signed main(){
cin>>A>>B>>C;
n=A+B+C;
for(int i=1;i<=n;i++)
for(int j=1;j<=3;j++) cin>>a[i][j];
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=3;j++) p[j].push(make_pair(a[i][j],i));
for(int i=1;i<=n;i++){
for(int i=1;i<=3;i++){
e[4][i]=e[i][4]=-inf;
for(int j=1;j<=3;j++)
e[i][j]=q[i][j].top().first;
}
if(A) e[1][4]=0;
if(B) e[2][4]=0;
if(C) e[3][4]=0;
SPFA();
int mx=-inf,id=0;
for(int i=1;i<=3;i++)
if(p[i].top().first+dis[i]>mx)
mx=p[i].top().first+dis[i],id=i;
ans+=mx;
int pos=id;
while(pre[pos]!=4){
int u=pos,v=pre[pos];
int x=q[u][v].top().second;
for(int i=1;i<=3;i++){
q[u][i].pop(make_pair(a[x][i]-a[x][u],x));
q[v][i].push(make_pair(a[x][i]-a[x][v],x));
}
pos=pre[pos];
}
if(pos==1) A--;
if(pos==2) B--;
if(pos==3) C--;
pos=p[id].top().second;
for(int i=1;i<=3;i++)
p[i].pop(make_pair(a[pos][i],pos));
for(int i=1;i<=3;i++)
q[id][i].push(make_pair(a[pos][i]-a[pos][id],pos));
}
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!