您的位置:首页 > 编程语言 > Go语言

Google 2015 APAC Round A Problem C - Addition

2015-09-01 16:05 399 查看
这个题算是一个比较经典的graph theory的问题,乍看之下好像要解线性方程组实际上不用。由于所有的方程都是两个两个连着的而且每个方程只有两个变量相加,因此我们可以确定: 给定a,b, 如果能够找到一条由a到b的奇数个边的路径,那么我们就能通过+-+-......-+的方式将方程挨个叠加相消最后得到a+b的值。但是也有一种情况例外,就是如果a到b没有路径,但是a和b的值可以各自求出那么a+b也是可以算出来的。

那么主要问题就是求a到b的路径问题了-- 这里的DFS非常诡异,因为我们最终目标是找到“奇数个边”的路径,然而环的存在可以打破当前搜索路径的奇偶性,因此图中的每个点有可能不止被访问一次。试想我在搜索a到b的路径过程中遇到一个奇数个边的环,那么整个之前路径的奇偶性全被打破了因而要重搜。但是要注意到每个点也至多被访问两次,而这两次访问分别代表了不同的奇偶性,因此总的算法复杂度O(E), E为边的个数。这个复杂度即使是大数据组3000个边的情形下也还是能比较快就得到结果的。

代码如下,重点部分有详细的注释,原谅我居然用了TreeNode类名,有可能是leetcode刷多了吧。

class TreeNode {

public:
TreeNode() {
color = -1;
times = 0;
}
static int result;
static unordered_map<string,TreeNode*> myMap;//用来存储所有的顶点和顶点的string名称

vector<TreeNode*> childs;//无向图每个定点的邻居
vector<int> vals;//每条边的方程数值
int color, times;//color 用来标记顶点,times是访问次数
void insert(TreeNode* a, int val) {
for (auto &b : childs)
if (a == b)
return;
childs.push_back(a);
vals.push_back(val);
}
static TreeNode* insertNode(string a) {
if (myMap.find(a) == myMap.end()) 
myMap[a] = new TreeNode();
return myMap[a];
}
static TreeNode* getNode(string a) {
if (myMap.find(a) != myMap.end())
return myMap[a];
else return NULL;
}
static bool prepDFS(TreeNode* node, int cur, int odd, TreeNode* target) {//每次调用DFS之前必须清除之前的标记
// clean up the tmp info
for (auto it = myMap.begin(); it != myMap.end(); it++) {
it->second->times = 0;
it->second->color = -1;
}
return DFS(node, cur, odd, target);
}
static bool DFS(TreeNode* node, int cur, int odd, TreeNode* target) {

node->times++;
node->color = odd;
int n  = node->childs.size();
odd = (odd + 1) % 2;
for (int i = 0; i < n; i++) 
if (node->childs[i]->color != odd && node->childs[i]->times < 2) {
int tmp = cur;
tmp += odd? node->vals[i] : -node->vals[i];
if (odd && node->childs[i] == target) {
TreeNode::result = tmp;
return true;
}
if (DFS(node->childs[i], tmp, odd, target))
return true;
}
return false;
}

static void init() {
result = 0;
//target = NULL;
myMap.clear();
}

};

//static memeber initialize

int TreeNode::result = 0;

//TreeNode* TreeNode::target = 0;

unordered_map<string,TreeNode*> TreeNode::myMap;

int parse(const string& str, string& a, string& b) {//解析输入字符串

int i = 0, prev = 0;
while (str[i++] != '+');
a = str.substr(0, i - 1);
prev = i;
while (i < str.size() && str[i] != '=')
i++;
b = str.substr(prev, i - prev);
if (i == str.size())return 0;
i++;
return atoi(str.substr(i, str.size() - i).c_str());

}

int main() {

int T, N, Q;
cin >> T;
for (int i = 0 ; i < T; i++) {
cin >> N;
string str, a, b;
TreeNode::init();

for (int j = 0 ; j < N; j++) {
cin >> str;
int tmp = parse(str, a, b);
TreeNode *na = TreeNode::insertNode(a), *nb = TreeNode::insertNode(b);
na->insert(nb, tmp);
nb->insert(na, tmp);
}
cin >> Q;
cout << "Case #" << i + 1 << ":" << endl;
for (int j = 0; j < Q; j++) {
cin >> str;
parse(str, a, b);
TreeNode *na = TreeNode::getNode(a), *nb = TreeNode::getNode(b);
if (na == NULL || nb == NULL)//如果这两个变量不存在,fuck off
continue;
if (TreeNode::prepDFS(na, 0, 0, nb))//如果路径存在,就输出
cout << str << "=" << TreeNode::result << endl;
else if (TreeNode::prepDFS(na, 0, 0, na)) {//如果路径不存在,那么只好看各自能否被求出
int t = TreeNode::result;
if (TreeNode::prepDFS(nb, 0, 0, nb)) {
cout << str << "=" << (TreeNode::result + t) / 2.0 << endl;
}
}
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  谷歌 dfs