-- Solution 4 CREATE PROCEDURE dbo.update_packages_and_bins (@solution tinyint ,@size smallint) AS Begin UPDATE dbo.packages SET bin_no = ( SELECT bno FROM #bins JOIN #packages on pid=bid WHERE pno=package_no ) WHERE EXISTS ( SELECT * FROM #packages WHERE pno = package_no ) UPDATE dbo.bins SET space_left = space_left - @size WHERE solution = @solution AND EXISTS ( SELECT * FROM #bins WHERE bno = bin_no ) End
CREATE PROCEDURE dbo.find_match (@solution tinyint ,@number_of_values tinyint ,@size smallint ,@bin_size smallint ) AS Begin Declare @count int Declare @space_count int Declare @max_val smallint Declare @val1 smallint Declare @val2 smallint Set @space_count = ( SELECT COUNT(*) FROM dbo.bins WHERE solution = @solution AND space_left = @size ) If @space_count = 0 Return If @number_of_values = 1 Begin Set @count = ( SELECT COUNT(*) FROM dbo.packages WHERE size = @size AND bin_no IS NULL ) If @count > @space_count Set @count = @space_count If @count > 0 Begin TRUNCATE TABLE #bins INSERT INTO #bins (bno) SELECT TOP (@count) bin_no FROM dbo.bins WHERE solution = @solution AND space_left = @size TRUNCATE TABLE #packages INSERT INTO #packages (pno) SELECT TOP (@count) package_no FROM dbo.packages WHERE bin_no IS NULL AND size = @size EXEC dbo.update_packages_and_bins @solution,@size End End If @number_of_values = 2 Begin Set @val1=@size/2; Set @val2=@size-@val1; Set @max_val=( SELECT MAX(size) FROM dbo.packages WHERE bin_no IS NULL ) While @val1>0 AND @val2 <= @max_val Begin If @val1=@val2 Set @count=( SELECT COUNT(*)/2 FROM dbo.packages WHERE size = @val1 AND bin_no IS NULL ) Else Set @count=( SELECT MIN(cnt) FROM ( SELECT COUNT(*) AS cnt FROM dbo.packages WHERE size = @val1 AND bin_no IS NULL UNION ALL SELECT COUNT(*) FROM dbo.packages WHERE size = @val2 AND bin_no IS NULL ) AS T ) If @space_count < @count Set @count=@space_count If @count > 0 Begin TRUNCATE TABLE #bins INSERT INTO #bins (bno) SELECT TOP (@count) bin_no FROM dbo.bins WHERE solution = @solution AND space_left = @size TRUNCATE TABLE #packages INSERT INTO #packages (pno) SELECT TOP (@count) package_no FROM dbo.packages WHERE bin_no IS NULL AND size = @val1 EXEC dbo.update_packages_and_bins @solution,@val1 TRUNCATE TABLE #packages INSERT INTO #packages (pno) SELECT TOP (@count) package_no FROM dbo.packages WHERE bin_no IS NULL AND size = @val2 EXEC dbo.update_packages_and_bins @solution,@val2 Set @space_count = ( SELECT COUNT(*) FROM dbo.bins WHERE solution = @solution AND space_left = @size ) If @space_count = 0 BREAK End Set @val1=@val1-1; Set @val2=@size-@val1; If NOT EXISTS ( SELECT * FROM dbo.packages WHERE bin_no IS NULL AND size=@val1 ) Begin Set @val1 = ( SELECT MAX(size) FROM dbo.packages WHERE bin_no IS NULL AND size < @val1 ) Set @val2=@size-@val1; End End End End
UPDATE dbo.packages SET bin_no = NULL DELETE FROM dbo.bins WHERE solution=4 Declare @space_count int Declare @count int Declare @solution tinyint Declare @bin_size smallint Declare @size smallint Declare @min_bins int Declare @extra_bins int Declare @number_of_values tinyint Set @solution = 4 Set @bin_size = 100 Set @min_bins = ( SELECT CEILING(SUM(size)*1.0/@bin_size) FROM dbo.packages ) INSERT INTO dbo.bins (solution, bin_no, space_left) SELECT @solution, n, @bin_size FROM dbo.numbers WHERE n BETWEEN 1 AND @min_bins CREATE TABLE #bins (bid int IDENTITY PRIMARY KEY,bno int NOT NULL) CREATE TABLE #packages (pid int IDENTITY PRIMARY KEY,pno int NOT NULL) SET NOCOUNT ON While EXISTS ( SELECT * FROM dbo.packages WHERE bin_no IS NULL ) Begin Set @number_of_values = 1 While @number_of_values < 3 Begin Set @size = ( SELECT MIN(space_left) FROM dbo.bins WHERE solution=@solution AND space_left>0 ) While @size > 0 Begin EXEC dbo.find_match @solution,@number_of_values,@size,@bin_size Set @size = ( SELECT MIN(space_left) FROM dbo.bins WHERE solution=@solution AND space_left>@size ) End Set @number_of_values = @number_of_values + 1 End Set @size = ( SELECT MAX(size) FROM dbo.packages WHERE bin_no IS NULL ) Set @count = ( SELECT COUNT(*) FROM dbo.packages WHERE size = @size AND bin_no IS NULL ) Set @space_count = ( SELECT COUNT(*) FROM dbo.bins WHERE solution = @solution AND space_left >= @size ) If @space_count = 0 Begin Set @extra_bins = CEILING(@count * @size * 1.0 / @bin_size) INSERT INTO dbo.bins (solution, bin_no, space_left) SELECT @solution, n, @bin_size FROM dbo.numbers WHERE n BETWEEN @min_bins+1 AND @min_bins+@extra_bins Set @min_bins = @min_bins + @extra_bins Set @space_count = @extra_bins End If @space_count < @count Set @count = @space_count TRUNCATE TABLE #bins INSERT INTO #bins (bno) SELECT TOP (@count) bin_no FROM dbo.bins WHERE solution = @solution AND space_left >= @size ORDER BY space_left ASC TRUNCATE TABLE #packages INSERT INTO #packages (pno) SELECT TOP (@count) package_no FROM dbo.packages WHERE bin_no IS NULL AND size = @size EXEC dbo.update_packages_and_bins @solution,@size End SET NOCOUNT OFF DROP TABLE #packages DROP TABLE #bins
Declare @bin_size smallint Set @bin_size=100 SELECT solution , COUNT(bin_no) AS number_of_bins , CEILING(SUM(@bin_size-space_left)*1.0/@bin_size) AS minimum , COUNT(bin_no) * 100.0 / CEILING(SUM(@bin_size-space_left)*1.0/@bin_size) AS percentage FROM dbo.bins GROUP BY solution ORDER BY solution
solution number_of_bins minimum percentage -------- -------------- --------------------- ------------------------------------- 1 37436 31011 120.718454741865789558543 2 31090 31011 100.254748315113991809357 3 31090 31011 100.254748315113991809357 4 31013 31011 100.006449324433265615426Wow! Near perfect! Only 2 bins more than a perfect fit.
Part 3 - Solution 3 | Part 5 - Solution 5
Back to SQL Server main menu. Mail your comments to gertjans@xs4all.nl.