(水)POJ-2531 DFS技巧

题目大意:网络中有n个节点,可以把这n个节点划分成两个集合subsets A和subsets B,同一个集合中的节点间进行

通讯没有时间损失,不同集合中的节点间进行通讯会有时间损失,求一种对n个结点的划分方法,使得时间的总损失

最大。


题目链接:点击打开链接


分析:观察数据范围发现N最大只有20,所以用DFS的话最多递归2^20次,每次递归都只要一些简单的操作,所以肯

定是可以不会超时的。于是我们就枚举出所有的不同分法的sum,取最大值。只要开个辅助数组vis[],vis[i]的值代表i节

点所在的集合。我们可以一开始将vis[]全初始化为0,即一开始全在集合0中(这样做的话就将 将许多元素分为2组 这

个问题变成了 是否从集合中取出i放入另一个集合),即全在0集合中,然后每次递归时只有2个入口,分别为第cur个

节点拿不拿出集合0,若不拿出集合0则没有变化,若拿出集合0放入集合1中则sum的变化值为:第cur个节点与集合0

中的权和-第cur个节点与集合1的权和。


附上代码:

#include<iostream>
#include<algorithm>
using namespace std;
#define Max 20+5
int G[Max][Max];
bool vis[Max];         //vis[i]的值表示i在哪个集合,一开始全为0集合
int n, ans;
int solve(int cur)
{
	int res = 0;
	for (int i = 1; i <= n; i++)
		if (vis[i]) res -= G[cur + 1][i];
		else res += G[cur + 1][i];
		return res;
}
void dfs(int cur,int sum)     //cur为当前位置,sum为当前的解
{
	if (sum > ans) ans = sum;
	if (cur == n) return;
	for (int i = 0; i < 2; i++)      //若i=0,代表i仍留在集合0中,则sum不变,否则记vis[i]=1,然后sum-=集合1中的总和,sum+=集合0中的总和
	{
		vis[cur + 1] = i;
		if (!i) dfs(cur + 1, sum);
		else dfs(cur + 1, sum + solve(cur));
		vis[cur + 1] = 0;
	}
	return;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d", &G[i][j]);
	dfs(0, 0);
	printf("%d\n", ans);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值