2024.7.1杂谈(数位dp,状压,匈牙利,网络流)

数位dp

通常是“统计 [L,R] 中满足某种特征的数的个数”的形式,用前缀和思想拆成两部分答案相减。

eg.板子数字计数

问题特点:

  • 目的是计数
  • 限制与数位相关
  • 用区间限制
  • 上界较大(如 1018

统计答案可以记搜,也可以用数组递推,从高到低每一位考虑可以填的数字统计答案。

状压

一些状态具有非 01 的状态,在数据规模不大的情况下可以用一个二进制数表示。状压枚举每种状态是 指数级 的复杂度。

状压可以拿来dp,也可以用于更简单地枚举状态。

eg.简单枚举状态
做dp

匈牙利算法

用于解决二分图最大匹配问题。

每次从左部点dfs到右部点:

(1)若右部点没有被匹配,用左部点和它匹配并返回匹配成功。

(2) 若右部点已被匹配,dfs它的匹配点(相当于看能否让它的匹配点换一个右部点匹配),若得到匹配成功的信息,让右部点和当前左部点匹配。

整个过程相当于找一条从左部点以及一条非匹配边开始的增广路。由于非匹配边和匹配边交错出现,每条增广路会让匹配数加一。

bool dfs(int u){
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v]) continue;
		vis[v]=true;
		if(!mat[v]||dfs(mat[v])){
			mat[v]=u;
			return true;
		}
	}
	return false;
}

网络流(最大流)

一般用 Dinic 算法,一般也没人专门卡它 除了加强版板子。理论上 O(n2m)(n为点数,m为边数),但实际跑不满,很快。

bool bfs(){
	memset(dep,0,sizeof dep);
	memcpy(cur,head,sizeof head);
	dep[s]=1;
	queue<int> q;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v;
			if(!dep[v]&&e[i].f){
				dep[v]=dep[u]+1;
				if(v==t) return true;
				q.push(v);
			}
		}
	}
	return dep[t];
}

int dfs(int u,int flow){
	if(u==t) return flow;
	int used=0;
	for(int &i=cur[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(dep[v]==dep[u]+1&&e[i].f){
			int rf=dfs(v,min(flow-used,e[i].f));
			used+=rf;
			e[i].f-=rf;
			e[i^1].f+=rf;
			if(used==flow) return used;
		}
	}
	return used;
}

void dinic(){
	while(bfs()) ans+=dfs(s,0x7fffffff);
}

cur 数组是当前弧优化, 必须加上复杂度才正确

bfs将图分层,保证增广轮数。

其他东西感性理解一下吧

posted @   RandomShuffle  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示