AT4144 [ARC098D] Donation【2019集训队作业】

本文解析了 AT4144 Donation (ARC098D) 的算法实现过程,通过构造一棵重构树并使用动态规划求解最优解。介绍了关键的数据结构和算法流程,包括节点比较、树的遍历及动态规划状态转移方程。
AT4144 [ARC098D] Donation【2019集训队作业】

C u = m a x { A u − B u , 0 } C_u=max\{A_u-B_u,0\} Cu=max{AuBu,0}

C u C_u Cu 的实际意义表示的是任意时刻 u u u 点的钱数都会大于 c u c_u cu

直接把 C C C 从小到大排序,然后建重构树即可。

d p x dp_x dpx 表示 x x x 子树内的答案。

那么有转移:

d p x = min ⁡ { s u m b x − s u m b y + max ⁡ { d p y , C x } } dp_x=\min\{sumb_x-sumb_y+\max\{dp_y,C_x\}\} dpx=min{sumbxsumby+max{dpy,Cx}}

s u m b x sumb_x sumbx 表示 x x x 子树内 B B B 的和。

选中的 y y y 就是我们最后遍历到的连通块,前面连通块遍历顺序不关心。

#include <bits/stdc++.h>
#define N 100005
using namespace std;
typedef long long ll;
int n,m;
struct node{
	int a,b,id;
}cc[N];
bool cmp_A(node x,node y){ 
	return x.a-x.b==y.a-y.b?x.id<y.id:x.a-x.b<y.a-y.b; 
}
vector<int> son[N],ed[N];
int fa[N],A[N],B[N],co[N];
ll ans[N],s[N];
int findf(int x){ return fa[x]==x?x:fa[x]=findf(fa[x]); }
void dfs(int x){
	int y; s[x]=B[x]; ans[x]=1e15;
	if(!ed[x].size()) ans[x]=max(A[x],B[x]); 
	for(int i=0;i<ed[x].size();i++){
		y=ed[x][i]; dfs(y); s[x]+=s[y];
	}
	for(int i=0;i<ed[x].size();i++){
		y=ed[x][i]; ans[x]=min(ans[x],s[x]-s[y]+max((ll)A[x]-B[x],ans[y]));
	}
//	cout<<x<<' '<<ans[x]<<'\n';
}
int main(){
//	freopen("test.in","r",stdin);
	cin>>n>>m;
	int u,v;
	for(int i=1;i<=n;i++) cin>>A[i]>>B[i],cc[i].a=A[i],cc[i].b=B[i],cc[i].id=i,fa[i]=i;
	for(int i=1;i<=m;i++){
		cin>>u>>v; 
		son[u].push_back(v),son[v].push_back(u);
	}
	sort(cc+1,cc+1+n,cmp_A);
	int x,y;
	for(int i=1;i<=n;i++){
		x=cc[i].id;
		for(int j=0;j<son[x].size();j++){
			y=son[x][j]; 
			if(A[y]-B[y]>A[x]-B[x]||(A[y]-B[y]==A[x]-B[x]&&y>x)) continue;
			if(findf(y)!=findf(x)){
				ed[x].push_back(fa[y]);
				fa[fa[y]]=fa[x];
			}
		}
	}
	dfs(findf(1));
	cout<<ans[findf(1)];
}
下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值