Problem
Six years ago, a robot, Bob, with infant's intelligence has been invented by an evil scientist, Alice.
Now the robot is six years old and studies in primary school. Addition is the first operation he learned in math. Due to his strong reasoning ability, he could now conclude a+b=12 from a=2 and b=10.
Alice wanted to test Bob's addition skills. Some equations were given to Bob in form of a=2, b=10, c=4, and Bob has to find out the answers of questions like a+b, a+c, etc.
Alice checked Bob's answers one by one in the test papers, and no mistake has been found so far, but Alice lost the given equations after a cup of coffee poured on them. However she has some of Bob's correct answers, e.g. a+b=12, a+c=6, c+d=5. She wants to continue with the checkable equations, e.g. b+d=11 could be concluded by a+b=12, a+c=6, c+d=5, and thus the question b+d is checkable.
To prevent the artificial intelligence technology from being under the control of Alice, you disguised yourself as her assistant. Now Alice wants you to figure out which of the rest of questions are checkable and their answers.
Input
The first line of the input gives the number of test cases, T. T test cases follow.
The first line of each test case contains a single integer N: the number of correctly answered questions. Each of the next N lines contain one correctly answered question in the form "x+y=z", where x and y are names of variables and z is a decimal integer.
The next line contains a single integer Q: the number of remaining questions. Each of the next Q lines contain one question in the form "x+y", where x and y are names of variables.
Output
For each test case, the first line of output contains "Case #x:", where x is the test case number (starting from 1). For each question in the input that was checkable, output a single line with the answer in the form "x+y=z", where x and y are names of variables andz is a decimal integer. Questions should be listed in the same order as they were given in the input. Please do NOT ignore duplicated questions, since Alice would fire you if you pointed any mistake of hers.
Limits
Names of variables are strings of lowercase English letters. Each name contains at most 10 characters.
-200000 ≤ z ≤ 200000
There is no contradiction in the answered questions.
Small dataset
T ≤ 10
N ≤ 10
Q ≤ 10
Large dataset
T ≤ 3
N ≤ 5000
Q ≤ 5000
Sample
将变量抽象为图顶点,等式抽象为图的边,看能否有奇数条边的通路即可。使用BFS搜索。
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unordered_map>
#include <queue>
#include <sstream>
using namespace std;
struct GEdge
{
int To; // the other end
int Value; // value of the edge
GEdge(int to, int val) : To(to), Value(val) {}
};
typedef vector<GEdge> EdgeArray;
vector<EdgeArray> g_Graph; // all edges from node i
unordered_map<string, int> g_Nodes; // all nodes
int g_NodeCount; // used to generate the node index
void add_edge(int node1, int node2, int val)
{
// undirected graph
g_Graph[node1].push_back(GEdge(node2, val));
g_Graph[node2].push_back(GEdge(node1, val));
}
int get_node(const string &name) // fetch or create a node
{
if (g_Nodes.count(name) > 0)
return g_Nodes[name];
return (g_Nodes[name] = g_NodeCount++);
}
bool bfs_search_path(int &val, int from, int to)
{
vector<bool> visited(g_NodeCount, false);
queue<GEdge> Q;
for (auto edge : g_Graph[from])
Q.push(edge);
while (!Q.empty())
{
GEdge cur = Q.front();
Q.pop();
int node = cur.To;
if (node == to)
{
val = cur.Value;
return true;
}
for (auto e : g_Graph[node])
{
for (auto ee : g_Graph[e.To]) // two loops to find odd edges
{
if (visited[ee.To])
continue;
visited[ee.To] = true;
Q.push(GEdge(ee.To, cur.Value - e.Value + ee.Value));
}
}
}
return false;
}
void work_single(istream &input, ostream &output)
{
int N;
input >> N;
// clear graph
g_Graph.clear();
g_Nodes.clear();
g_NodeCount = 0;
g_Graph.resize(N * 2);
// read and build graph
for (int i = 0; i < N; i++)
{
string line;
input >> line;
// find +,= position
size_t j;
for (j = 0; j < line.length(); j++)
{
if (line[j] == '+' || line[j] == '=')
line[j] = ' ';
}
string name1, name2;
int val;
istringstream line_stream(line);
line_stream >> name1 >> name2 >> val;
// add edge
int node1 = get_node(name1);
int node2 = get_node(name2);
add_edge(node1, node2, val);
}
int Q;
input >> Q;
for (int i = 0; i < Q; i++)
{
string line;
input >> line;
// find +
size_t j;
for (j = 0; j < line.length(); j++)
{
if (line[j] == '+')
break;
}
string name1 = line.substr(0, j);
string name2 = line.substr(j + 1, line.length() - j - 1);
if (g_Nodes.count(name1) == 0 || g_Nodes.count(name2) == 0)
continue;
int node1 = get_node(name1);
int node2 = get_node(name2);
int val;
if (bfs_search_path(val, node1, node2))
output << line << "=" << val << endl;
}
}
void work(istream &input, ostream &output)
{
int case_count;
input >> case_count;
for (int i = 0; i < case_count; i++)
{
output << "Case #" << i + 1 << ":" << endl;
work_single(input, output);
}
}
int main(int argc, char *argv[])
{
bool use_stdio = false;
if (use_stdio)
work(cin, cout);
else
{
ifstream input("C-large-practice.in");
ofstream output("C-large-practice.out");
work(input, output);
}
return 0;
}