给定大小为N的数组。任务是将给定的数组划分为两个子集,以使两个子集中的所有元素的平均值相等。如果不存在这样的分区,则打印-1。否则,请打印分区。如果存在多个解决方案,请在第一个子集的长度最小的位置打印解决方案。如果仍然有平局,则打印第一个子集在字典上最小的分区。
例子:
Input : vec[] = {1, 7, 15, 29, 11, 9}
Output : [9, 15] [1, 7, 11, 29]
Explanation : Average of the both the subsets is 12
Input : vec[] = {1, 2, 3, 4, 5, 6}
Output : [1, 6] [2, 3, 4, 5].
Explanation : Another possible solution is [3, 4] [1, 2, 5, 6],
but print the solution whose first subset is lexicographically
smallest.
观察:
如果我们直接计算某个子集的平均值,然后将其与另一个子集的平均值进行比较,由于编译器的精度问题,则会发生意外结果。例如,5/3 = 1.66666 ..和166/100 = 1.66。一些编译器可能将它们视为相同,而另一些则不会。
设两个子集的总和为sub1和sub2,其大小为s1和s2。如果它们的平均值相等,则sub1 / s1 = sub2 / s2。这意味着sub1 * s2 = sub2 * s1。
同样,上述两个子集的总和= sub1 + sub2,而s2 =总大小– s1。
通过简化以上内容,我们得到
(sub1/s1) = (sub1+sub2)/ (s1+s2) = (total sum) / (total size).
现在,这个问题简化为以下事实:如果我们可以选择特定的尺寸
总和等于当前子集的总和的子集,我们完成了。
方法 :
让我们定义函数partition(ind,curr_sum,curr_size),如果可以使用索引等于ind且大小等于curr_size和sum等于curr_sum的元素构造子集,则该函数返回true。
此递归关系可以定义为:
partition(ind, curr_sum, curr_size) = partition(ind+1, curr_sum, curr_size) || partition(ind+1, curr_sum – val[ind], curr_size-1).
上述等式右侧的两部分表示是否在索引ind处包含元素。
这与经典子集和问题有所不同,在经典子集和问题中,一次又一次地评估子问题。因此,我们记住了子问题,并将其变成了动态编程解决方案。
C++14
// C++ program to Partition an array of
// non-negative integers into two subsets
// such that average of both the subsets are equal
#include
using namespace std;
vector > > dp;
vector res;
vector original;
int total_size;
// Function that returns true if it is possible to
// use elements with index = ind to construct a set of s
// ize = curr_size whose sum is curr_sum.
bool possible(int index, int curr_sum, int curr_size)
{
// base cases
if (curr_size == 0)
return (curr_sum == 0);
if (index >= total_size)
return false;
// Which means curr_sum cant be found for curr_size
if (dp[index][curr_sum][curr_size] == false)
return false;
if (curr_sum >= original[index]) {
res.push_back(original[index]);
// Checks if taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum -
original[index],
curr_size - 1))
return true;
res.pop_back();
}
// Checks if not taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum, curr_size))
return true;
// If no solution has been found
return dp[index][curr_sum][curr_size] = false;
}
// Function to find two Partitions having equal average
vector > partition(vector& Vec)
{
// Sort the vector
sort(Vec.begin(), Vec.end());
original.clear();
original = Vec;
dp.clear();
res.clear();
int total_sum = 0;
total_size = Vec.size();
for (int i = 0; i < total_size; ++i)
total_sum += Vec[i];
// building the memoization table
dp.resize(original.size(), vector >
(total_sum + 1, vector(total_size, true)));
for (int i = 1; i < total_size; i++) {
// Sum_of_Set1 has to be an integer
if ((total_sum * i) % total_size != 0)
continue;
int Sum_of_Set1 = (total_sum * i) / total_size;
// We build our solution vector if its possible
// to find subsets that match our criteria
// using a recursive function
if (possible(0, Sum_of_Set1, i)) {
// Find out the elements in Vec, not in
// res and return the result.
int ptr1 = 0, ptr2 = 0;
vector res1 = res;
vector res2;
while (ptr1 < Vec.size() || ptr2 < res.size())
{
if (ptr2 < res.size() &&
res[ptr2] == Vec[ptr1])
{
ptr1++;
ptr2++;
continue;
}
res2.push_back(Vec[ptr1]);
ptr1++;
}
vector > ans;
ans.push_back(res1);
ans.push_back(res2);
return ans;
}
}
// If we havent found any such subset.
vector > ans;
return ans;
}
// Function to print partitions
void Print_Partition(vector > sol)
{
// Print two partitions
for (int i = 0; i < sol.size(); i++) {
cout << "[";
for (int j = 0; j < sol[i].size(); j++) {
cout << sol[i][j];
if (j != sol[i].size() - 1)
cout << " ";
}
cout << "] ";
}
}
// Driver code
int main()
{
vector Vec = { 1, 7, 15, 29, 11, 9 };
vector > sol = partition(Vec);
// If partition possible
if (sol.size())
Print_Partition(sol);
else
cout << -1;
return 0;
}
Java
// Java program to Partition an array of
// non-negative integers into two subsets
// such that average of both the subsets are equal
import java.io.*;
import java.util.*;
class GFG
{
static boolean[][][] dp;
static Vector res = new Vector<>();
static int[] original;
static int total_size;
// Function that returns true if it is possible to
// use elements with index = ind to construct a set of s
// ize = curr_size whose sum is curr_sum.
static boolean possible(int index, int curr_sum,
int curr_size)
{
// base cases
if (curr_size == 0)
return (curr_sum == 0);
if (index >= total_size)
return false;
// Which means curr_sum cant be found for curr_size
if (dp[index][curr_sum][curr_size] == false)
return false;
if (curr_sum >= original[index])
{
res.add(original[index]);
// Checks if taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum - original[index],
curr_size - 1))
return true;
res.remove(res.size() - 1);
}
// Checks if not taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum, curr_size))
return true;
// If no solution has been found
return dp[index][curr_sum][curr_size] = false;
}
// Function to find two Partitions having equal average
static Vector> partition(int[] Vec)
{
// Sort the vector
Arrays.sort(Vec);
original = Vec;
res.clear();
int total_sum = 0;
total_size = Vec.length;
for (int i = 0; i < total_size; ++i)
total_sum += Vec[i];
// building the memoization table
dp = new boolean[original.length][total_sum + 1][total_size];
for (int i = 0; i < original.length; i++)
for (int j = 0; j < total_sum + 1; j++)
for (int k = 0; k < total_size; k++)
dp[i][j][k] = true;
for (int i = 1; i < total_size; i++)
{
// Sum_of_Set1 has to be an integer
if ((total_sum * i) % total_size != 0)
continue;
int Sum_of_Set1 = (total_sum * i) / total_size;
// We build our solution vector if its possible
// to find subsets that match our criteria
// using a recursive function
if (possible(0, Sum_of_Set1, i))
{
// Find out the elements in Vec, not in
// res and return the result.
int ptr1 = 0, ptr2 = 0;
Vector res1 = res;
Vector res2 = new Vector<>();
while (ptr1 < Vec.length || ptr2 < res.size())
{
if (ptr2 < res.size() &&
res.elementAt(ptr2) == Vec[ptr1])
{
ptr1++;
ptr2++;
continue;
}
res2.add(Vec[ptr1]);
ptr1++;
}
Vector> ans = new Vector<>();
ans.add(res1);
ans.add(res2);
return ans;
}
}
// If we havent found any such subset.
Vector> ans = new Vector<>();
return ans;
}
// Function to print partitions
static void Print_Partition(Vector> sol)
{
// Print two partitions
for (int i = 0; i < sol.size(); i++)
{
System.out.print("[");
for (int j = 0; j < sol.elementAt(i).size(); j++)
{
System.out.print(sol.elementAt(i).elementAt(j));
if (j != sol.elementAt(i).size() - 1)
System.out.print(" ");
}
System.out.print("]");
}
}
// Driver Code
public static void main(String[] args)
{
int[] Vec = { 1, 7, 15, 29, 11, 9 };
Vector> sol = partition(Vec);
// If partition possible
if (sol.size() > 0)
Print_Partition(sol);
else
System.out.println("-1");
}
}
// This code is contributed by
// sanjeev2552
Python3
# Python3 program to partition an array of
# non-negative integers into two subsets
# such that average of both the subsets are equal
dp = []
res = []
original = []
total_size = int(0)
# Function that returns true if it is possible
# to use elements with index = ind to construct
# a set of s ize = curr_size whose sum is curr_sum.
def possible(index, curr_sum, curr_size):
index = int(index)
curr_sum = int(curr_sum)
curr_size = int(curr_size)
global dp, res
# Base cases
if curr_size == 0:
return (curr_sum == 0)
if index >= total_size:
return False
# Which means curr_sum cant be
# found for curr_size
if dp[index][curr_sum][curr_size] == False:
return False
if curr_sum >= original[index]:
res.append(original[index])
# Checks if taking this element
# at index i leads to a solution
if possible(index + 1,
curr_sum - original[index],
curr_size - 1):
return True
res.pop()
# Checks if not taking this element at
# index i leads to a solution
if possible(index + 1, curr_sum, curr_size):
return True
# If no solution has been found
dp[index][curr_sum][curr_size] = False
return False
# Function to find two partitions
# having equal average
def partition(Vec):
global dp, original, res, total_size
# Sort the vector
Vec.sort()
if len(original) > 0:
original.clear()
original = Vec
if len(dp) > 0:
dp.clear()
if len(res) > 0:
res.clear()
total_sum = 0
total_size = len(Vec)
for i in range(total_size):
total_sum += Vec[i]
# Building the memoization table
dp = [[[True for _ in range(total_size)]
for _ in range(total_sum + 1)]
for _ in range(len(original))]
for i in range(1, total_size):
# Sum_of_Set1 has to be an integer
if (total_sum * i) % total_size != 0:
continue
Sum_of_Set1 = (total_sum * i) / total_size
# We build our solution vector if its possible
# to find subsets that match our criteria
# using a recursive function
if possible(0, Sum_of_Set1, i):
# Find out the elements in Vec,
# not in res and return the result.
ptr1 = 0
ptr2 = 0
res1 = res
res2 = []
while ptr1 < len(Vec) or ptr2 < len(res):
if (ptr2 < len(res) and
res[ptr2] == Vec[ptr1]):
ptr1 += 1
ptr2 += 1
continue
res2.append(Vec[ptr1])
ptr1 += 1
ans = []
ans.append(res1)
ans.append(res2)
return ans
# If we havent found any such subset.
ans = []
return ans
# Driver code
Vec = [ 1, 7, 15, 29, 11, 9 ]
sol = partition(Vec)
if len(sol) > 0:
print(sol)
else:
print("-1")
# This code is contributed by saishashank1
C#
// C# program to Partition an array of
// non-negative integers into two subsets
// such that average of both the subsets are equal
using System;
using System.Collections;
class GFG{
static bool[,,] dp;
static ArrayList res = new ArrayList();
static int[] original;
static int total_size;
// Function that returns true if it is possible to
// use elements with index = ind to construct a set of s
// ize = curr_size whose sum is curr_sum.
static bool possible(int index, int curr_sum,
int curr_size)
{
// base cases
if (curr_size == 0)
return (curr_sum == 0);
if (index >= total_size)
return false;
// Which means curr_sum cant be
// found for curr_size
if (dp[index, curr_sum, curr_size] == false)
return false;
if (curr_sum >= original[index])
{
res.Add(original[index]);
// Checks if taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum -
original[index], curr_size - 1))
return true;
res.Remove(res[res.Count - 1]);
}
// Checks if not taking this element at
// index i leads to a solution
if (possible(index + 1, curr_sum, curr_size))
return true;
dp[index, curr_sum, curr_size] = false;
// If no solution has been found
return dp[index, curr_sum, curr_size];
}
// Function to find two Partitions
// having equal average
static ArrayList partition(int[] Vec)
{
// Sort the vector
Array.Sort(Vec);
original = Vec;
res.Clear();
int total_sum = 0;
total_size = Vec.Length;
for(int i = 0; i < total_size; ++i)
total_sum += Vec[i];
// Building the memoization table
dp = new bool[original.Length,
total_sum + 1,
total_size];
for(int i = 0; i < original.Length; i++)
for(int j = 0; j < total_sum + 1; j++)
for(int k = 0; k < total_size; k++)
dp[i, j, k] = true;
for(int i = 1; i < total_size; i++)
{
// Sum_of_Set1 has to be an integer
if ((total_sum * i) % total_size != 0)
continue;
int Sum_of_Set1 = (total_sum * i) / total_size;
// We build our solution vector if its possible
// to find subsets that match our criteria
// using a recursive function
if (possible(0, Sum_of_Set1, i))
{
// Find out the elements in Vec, not in
// res and return the result.
int ptr1 = 0, ptr2 = 0;
ArrayList res1 = new ArrayList(res);
ArrayList res2 = new ArrayList();
while (ptr1 < Vec.Length || ptr2 < res.Count)
{
if (ptr2 < res.Count &&
(int)res[ptr2] == Vec[ptr1])
{
ptr1++;
ptr2++;
continue;
}
res2.Add(Vec[ptr1]);
ptr1++;
}
ArrayList ans = new ArrayList();
ans.Add(res1);
ans.Add(res2);
return ans;
}
}
// If we havent found any such subset.
ArrayList ans2 = new ArrayList();
return ans2;
}
// Function to print partitions
static void Print_Partition(ArrayList sol)
{
// Print two partitions
for(int i = 0; i < sol.Count; i++)
{
Console.Write("[");
for(int j = 0; j < ((ArrayList)sol[i]).Count; j++)
{
Console.Write((int)((ArrayList)sol[i])[j]);
if (j != ((ArrayList)sol[i]).Count - 1)
Console.Write(" ");
}
Console.Write("] ");
}
}
// Driver Code
public static void Main(string[] args)
{
int[] Vec = { 1, 7, 15, 29, 11, 9 };
ArrayList sol = partition(Vec);
// If partition possible
if (sol.Count > 0)
Print_Partition(sol);
else
Console.Write("-1");
}
}
// This code is contributed by rutvik_56
[9 15] [1 7 11 29]