题目大意:网络中有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; }