Sheet

Pages: 12
Apr 21, 2022 at 2:51pm
Hello, I'm a C++ beginner trying to solve this problem.

You have a spreadsheet and some cells are inserted with formula. A cell without formula has initial value.However, some cells have buggy formula. The formula of several cells might depend on each other and results in reference error. For example, cell A1 has formula B1 + 2, cell B1 has formula C1 + 2, cell C1 has formula A1 + 2, then the spreadsheet reports reference error.If a cell has formula depending a cell with reference error, itself encounters reference error as well. For example, cell C1 has reference error, cell C4 has formula C1 + 2, then C4 has reference error.

Given a spreadsheet, please output results of all cells.

Input Format

The first line contains two integer : N,M the number of cells in the spreadsheet and the number of cells with formula.

The cells are labeled with 1,2,...N (instead of the usual way we see in spreadsheet applications).

The following M lines describes the formula, for each line is either:
A x1 y - Cell x1 has value y
B x1 x2 y - Cell x1 has formula: cell x2 + value y
...

Output Format

For each cell, please output "#REF!" if it has reference error; otherwise, output its value.

Sample Input

10 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8

Sample Output

10
30
60
#REF!
#REF!
#REF!
42
#REF!
108
0

Explanation 0

The formula and result of each cell is listed below:

cell id formula result
1 10 10
2 cell 1 + 20 30
3 cell 2 + 30 60
4 cell 6 + 2 reference error
5 cell 4 + 2 reference error
6 cell 5 + 2 reference error
7 cell 1 + cell 2 + 2 42
8 cell 7 + cell 6 + 3 reference error
9 cell 1 + cell 2 + cell 3 + 8 108
10 (empty cell) 0

Sorry the problem is quite long.
I'd like to solve it step by step, first, how to implement the cin that got three items in a line, and, is there any hint on solving this problem efficiently? Appreciate anyone's help.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 #include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
    int N,M;
    cin>>N>>M;
    while(M--)
    return 0;
}
Last edited on Apr 21, 2022 at 2:51pm
Apr 21, 2022 at 4:16pm
The first task is to read in the input into a possible structure. One way to do this is as below. It uses a stuct for each cell then details references to the other cells and the final value to be added. This code will read and store the entered data and then display it. This may be a useful starting point.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <vector>

struct Form {
	std::vector<unsigned> cells;
	int val {};
};

int main() {
	unsigned N {}, M {};

	std::cin >> N >> M;

	std::vector<Form> calc(N);

	for (unsigned n {}; n < N; ++n) {
		char type {};
		unsigned cellno {};

		std::cin >> type >> cellno;

		for (unsigned f {}, nocells {type - 'A' + 0U}; f < nocells; ++f) {
			unsigned cell {};

			std::cin >> cell;
			calc[cellno - 1].cells.push_back(cell);
		}

		std::cin >> calc[cellno - 1].val;
	}

	for (unsigned cell {1}; const auto& [cells, val] : calc) {
		std::cout << cell++ << "  ";

		for (const auto& c : cells)
			std::cout << c << "  ";

		std::cout << val << '\n';
	}
}


Given the input of:


10 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8
A 10 10


displays:


1  10
2  1  20
3  2  30
4  6  2
5  4  2
6  5  2
7  1  2  2
8  7  6  3
9  1  2  3  8
10  10

Last edited on Apr 21, 2022 at 4:17pm
Apr 22, 2022 at 7:42am
wow it seems a bit complicated, may I ask the purpose of + 0U in line 22?
Apr 22, 2022 at 8:37am
To convert int to unsigned int. type - '0' gives a type of int - but nocells is of type unsigned. Using {} as an initializer requires that narrowing can't occur (ie signed int to unsigned) so + 0U (U for unsigned) type converts to unsigned.
Apr 22, 2022 at 10:51am
One simple recursive solution could be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <vector>
#include <utility>
#include <set>

struct Form {
	std::vector<unsigned> cells;
	int val {};
};

struct Result {
	int res {};
	bool good {};
};

// Note cell starts at 1!
Result eval(int cell, const std::vector<Form>& cls, std::set<int> visit) {
	if (!cls[cell - 1].cells.empty() && !visit.insert(cell).second)
		return {0, false};

	Result res {cls[cell - 1].val, true};

	for (const auto& c : cls[cell - 1].cells)
		if (const auto res1 {eval(c, cls, visit)}; res1.good)
			res.res += res1.res;
		else
			return {0, false};

	return res;
}

int main() {
	unsigned N {}, M {};

	std::cin >> N >> M;		// M not used

	std::vector<Form> calc(N);

	for (unsigned n {}; n < N; ++n) {
		char type {};
		unsigned cellno {};

		std::cin >> type >> cellno;

		for (unsigned f {}, nocells {type - 'A' + 0U}; f < nocells; ++f) {
			unsigned cell {};

			std::cin >> cell;
			calc[cellno - 1].cells.push_back(cell);
		}

		std::cin >> calc[cellno - 1].val;
	}

	for (unsigned cell {1}; cell <= calc.size(); ++cell) {
		std::set<int> visit;

		std::cout << cell << "  ";

		if (const auto res {eval(cell, calc, visit)}; res.good)
			std::cout << res.res << '\n';
		else
			std::cout << "#REF#\n";
	}
}



9 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8
1  10
2  30
3  60
4  #REF#
5  #REF#
6  #REF#
7  42
8  #REF#
9  108

Last edited on Apr 22, 2022 at 10:57am
Apr 23, 2022 at 8:46am
Hi, I got segmentation fault when running this code, is it because of the complexity?
Last edited on Apr 23, 2022 at 8:46am
Apr 23, 2022 at 9:22am
What os/compiler are you using? It works OK with VS2022

Note that in the original data, N is 10 but there are only 9 cells listed.



Apr 23, 2022 at 9:48am
I'm running it using c++20 , does segmentation fault imply stack overflow,
I changed vector<Form> calc(N) in line 37 to vector<Form> calc(N+1) and the compile message became abort called.
Last edited on Apr 26, 2022 at 5:07am
Apr 23, 2022 at 10:17am
What is the data being used? The data provided had the cell number starting at 1 and ending at N. If this scheme is not used for the actual data being used, then this will be an error - as the cell number is used to index into the vector.

Apr 23, 2022 at 11:38am
This version is based on a std::map rather than a vector, so it doesn't matter re the cell number.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <vector>
#include <utility>
#include <set>
#include <map>

struct Form {
	std::vector<unsigned> cells;
	int val {};
};

struct Result {
	int res {};
	bool good {};
};

using Cells = std::map<unsigned, Form>;

Result eval(int cell, Cells& cls, std::set<int> visit) {
	if (!cls[cell].cells.empty() && !visit.insert(cell).second)
		return {0, false};

	Result res {cls[cell].val, true};

	for (const auto& c : cls[cell].cells)
		if (const auto res1 {eval(c, cls, visit)}; res1.good)
			res.res += res1.res;
		else
			return {0, false};

	return res;
}

int main() {
	unsigned N {}, M {};

	std::cin >> N >> M;		// M not used

	Cells calc;

	for (unsigned n {}; n < N; ++n) {
		char type {};
		unsigned cellno {};

		std::cin >> type >> cellno;

		for (unsigned f {}, nocells {type - 'A' + 0U}; f < nocells; ++f) {
			unsigned cell {};

			std::cin >> cell;
			calc[cellno].cells.push_back(cell);
		}

		std::cin >> calc[cellno].val;
	}

	for (auto& cell : calc) {
		std::set<int> visit;

		std::cout << cell.first << "  ";

		if (const auto res {eval(cell.first, calc, visit)}; res.good)
			std::cout << res.res << '\n';
		else
			std::cout << "#REF#\n";
	}
}



9 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8
1  10
2  30
3  60
4  #REF#
5  #REF#
6  #REF#
7  42
8  #REF#
9  108

Last edited on Apr 23, 2022 at 11:39am
Apr 23, 2022 at 12:53pm
oh yes I see, that should be the problem.So what to do with empty cells. It can't be solved by adding the line 65~66 to deal with empty cells.I'm still trying to understand the rest of the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <vector>
#include <utility>
#include <set>

struct Form {
    std::vector<unsigned> cells;
    int val {};
};

struct Result {
    int res {};
    bool good {};
};

// Note cell starts at 1!
Result eval(int cell, const std::vector<Form>& cls, std::set<int> visit) {
    if (!cls[cell - 1].cells.empty() && !visit.insert(cell).second)
        return {0, false};

    Result res {cls[cell - 1].val, true};

    for (const auto& c : cls[cell - 1].cells)
        if (const auto res1 {eval(c, cls, visit)}; res1.good)
            res.res += res1.res;
        else
            return {0, false};

    return res;
}

int main() {
    unsigned N {}, M {};

    std::cin >> N >> M;        // M not used

    std::vector<Form> calc(N+1);

    for (unsigned n {}; n < N; ++n) {
        char type {};
        unsigned cellno {};

        std::cin >> type >> cellno;

        for (unsigned f {}, nocells {type - 'A' + 0U}; f < nocells; ++f) {
            unsigned cell {};

            std::cin >> cell;
            calc[cellno - 1].cells.push_back(cell);
        }

        std::cin >> calc[cellno - 1].val;
    }

    for (unsigned cell {1}; cell <= calc.size(); ++cell) {
        std::set<int> visit;

        std::cout << cell << "  ";

        if (const auto res {eval(cell, calc, visit)}; res.good)
            std::cout << res.res << '\n';
        else
            std::cout << "#REF#\n";     
    }
    for ( ;N<M; N++) 
         std::cout<<0<< '\n';
}
Last edited on Apr 23, 2022 at 12:54pm
Apr 23, 2022 at 1:06pm
Does the map version above work?
Apr 23, 2022 at 1:25pm
The map version shows one abort called, one wrong answer and few terminated due to time out in test cases.
Apr 23, 2022 at 1:37pm
Do you have the test data used?
Apr 23, 2022 at 1:47pm
I can only see the test data 0,

10 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8

and it shows abort called.
Apr 23, 2022 at 4:06pm
I think I've mis-read the meaning of N, M. For L37 (of the map version) try (reverse N, M):

 
std::cin >> M >> N;



10 9
A 1 10
B 2 1 20
B 3 2 30
B 4 6 2
B 5 4 2
B 6 5 2
C 7 1 2 2
C 8 7 6 3
D 9 1 2 3 8
1  10
2  30
3  60
4  #REF#
5  #REF#
6  #REF#
7  42
8  #REF#
9  108

Last edited on Apr 23, 2022 at 4:17pm
Apr 24, 2022 at 5:37am
Hi, now it did pass two test cases, but the rest shows wrong answer and terminated due to time out.
Apr 24, 2022 at 12:01pm
Well that points to a probable problem with the algorithm used. This could be simple and easily fixed - or major requiring a re-design. However without the data that doesn't process as expected then I'm out. Good luck!

Apr 24, 2022 at 1:43pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <string>
using namespace std;

//======================================================================

struct Cell
{
   long long value = 0;
   set<int> parents;
   bool refError = false;
};

//======================================================================

vector<Cell> readFormulae()
{
   string dummy;
   int N, M;
   cin >> N >> M;   getline( cin, dummy );
   vector<Cell> result( 1 + N );

   for ( int f = 0; f < M; f++ )
   {
      string line;
      getline( cin, line );
      stringstream ss( line );
      int i;
      ss >> dummy >> i;
      ss >> result[i].value;
      for ( int x; ss >> x; )
      {
         result[i].parents.insert( result[i].value );
         result[i].value = x;
      }
   }
   return result;
}

//======================================================================

bool getValue( int n, vector<Cell> &cells, set<int> &parents )
{
   for ( int c : cells[n].parents )
   {
      //      ref error                   cycle                         subtree error
      if ( cells[c].refError || !parents.insert( c ).second || !getValue( c, cells, parents ) )
      {
         cells[n].refError = true;
         return false;
      }
      cells[n].value += cells[c].value;
   }
   cells[n].parents.clear();
   return true;
}

//======================================================================

int main()
{
   vector<Cell> cells = readFormulae();

   for ( int n = 1; n < cells.size(); n++ )
   {
      set<int> parents{ n };
      getValue( n, cells, parents );
      if ( cells[n].refError ) cout << "#REF!" << '\n';
      else                     cout << cells[n].value << '\n';
   }
}

//====================================================================== 


10
30
60
#REF!
#REF!
#REF!
42
#REF!
108
0

Apr 24, 2022 at 2:07pm
Hi lastchance, when trying your code it shows 4 out of 10 test cases correct and the others got wrong answers.
Pages: 12