3.8 电路布线

问题描述:
       一块电路板上、下两端分别有n个接线柱,依据电路设计,要求使用导线将(i, a(i)) 将上端接线柱i与下端接线柱a(i)连接,有若干层,但保证第一层中连线的数量最大且不相交,Net = {(i, a(i)) 1 <= i <= n}即最大不相交子集。
       书上讲的过于理论化,难以看懂,我按照我的理解分析。

       电路布线其实和0-1背包很像,如下图
在这里插入图片描述
       我想应该看得懂,出现交叉的情况了,为何会出现交叉的情况,本质上红线的下接线柱只能在黑线的左边以保证不相交。
       所以红线只能接在左边,我们再看,假设dp(i, j)表示上接线柱 <= i ,下接线柱 <= j的连线的集合,此时遇到(i, a(i)),分两种情况,此时能否纳入呢?
1. j < a[i]   说明不能不能纳入, 否则会产 生相交即 取dp[i - 1][j]
2. j >= a[i] 就就一定可取,不一定,分取与不取:
    取则dp[i][j] --> dp[i - 1][a[i ] - 1] + 1;不取即相当于不纳入即 取dp[i - 1][j]。
    //取即在前一个(dp[i - 1][a[i] - 1])的基础上 + 1即可
3. 初始化很简单在i == 1时,如果 j < a[1] 则 dp[i][j] = 0,否则置1

源代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

int a[1024], dp[1024][1024];

int main()
{
	int i, j, n;
	scanf("%d", &n);
	for(i = 1; i <= n; ++i)
	{
		scanf("%d", &a[i]);
	}
//	i == 1时     0               j <  a[i](无法布线) 
//	dp[i][j] = {
//				 1               j >= a[i]((i, a[i]) 属于 MNS(i, j)) 
//	i >  1时 	dp[i - 1][j]	 j <  a[i]((i, a[i]) 不属于 MNS(i, j), 取前)
//	dp[i][j] = {
//				max(dp[i - 1][j], dp[i - 1][a[i] - 1] + 1)     j >= a[i]((i, a[i]) 属于 MNS(i, j), MNS(i, j) - {(i, a[i])} 为 N(i, a[i])最大不相交子集)
	for(j = 0; j < a[1]; ++j)  dp[1][j] = 0;
	for(j = a[1]; j <= n; ++j) dp[1][j] = 1;
	for(i = 2; i <= n; ++i)
	{
		for(j = 0; j < a[i]; ++j)  dp[i][j] = dp[i - 1][j];
		for(j = a[i]; j <= n; ++j) dp[i][j] = max(dp[i - 1][j], dp[i - 1][a[i] - 1] + 1);
	}
//	dp[n][n] = max(dp[n - 1][n], dp[n - 1][a[n] - 1] + 1);
	printf("%d\n", dp[n][n]);
	return 0;
}
/*
10
8 7 4 2 5 1 9 3 10 6
*/
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值