Problem C. Addition - APAC Test 2015 Round A(奇数边)

链接

https://code.google.com/codejam/contest/3214486/dashboard#s=p2

题意

题意

给定N个表达式,形如: a+b=3
又给出M个表达式,形如: a+c 。问每一个能否由已知的表达式得到,并给出结果

思路

明显的图论题。
从样例考虑:

a+b=3

b+c=3

c+d=3

对于每一个等式,如: a+b=3 ,其中 a , b之间存在关系,并且是双向关系,于是我们连一条双向边。
对于上述的3个表达式建图如下:
1
首先,求 a+c 。从表达式中我们可以看出:

a+b=3

b+c=3

只能求出 ac=0

a+d 。我们已经得到了 ac=0 ,然后又有 c+d=3 ,于是得到 a+d=3

(1) 结合上面的图观察,我们可以得到这样一个结论:当从 x y的时候只经过奇数条边,那么我们可以求出 x+y

(2) 注意还有一个特殊情况就是: x+x=a y+y=b ,那么我们可以得到 x+y=a+b2

情况2很好处理,我们现在只需要处理情况1:即存在一条从 x y的路径,只经过奇数条边。

因为图可能有环,写到这里就很迷了:可能从 x y直接存在一条无环的奇数路径,也可能存在一条无环的偶数路径,但是图中有奇数环,这时候再去绕一下就好了。不知道该怎么去处理环。

然后翻了一下大神的代码:直接BFS。
Step1: 首先,从起点走1条边,可以到达若干个点 S ,将集合S中的所有点标记为已访问。
Step2: 然后从 S 中所有点出发,每次走2条边可以到达若干个点S1,将 S1 中的点标记为已访问。循环这个走2条边的过程直到发现无解或者找到我们的解。
该解法解决了2个问题:
1. 确保从 x y一定只经过奇数条边
2. 避免了直接BFS带来的可能不会从奇数环绕一圈的问题

代码

#include <bits/stdc++.h>

using namespace std;

inline int in() {int x; scanf("%d", &x); return x;}
#define pr(x) {cout << #x << ' ' << x << endl;}

const int maxn = 20000 + 5;

struct Edge {
    int u, v, w;
    Edge() {}
    Edge(int a, int b, int c) : u(a), v(b), w(c) {}
    bool operator < (Edge& rh) {
        return w < rh.w;
    }
};

int n, m, vn;
unordered_map<string, int> si;
unordered_map<int, string> is;
vector<Edge> edges;
vector<int> G[maxn];
int vis[maxn];

void AddDoubleEdge(int u, int v, int w) {
    edges.push_back(Edge(u, v, w));
    G[u].push_back(edges.size() - 1);
    edges.push_back(Edge(v, u, w));
    G[v].push_back(edges.size() - 1);
}

int Hash(string s) {
    if (si.find(s) == si.end()) {
        si[s] = ++vn;
        is[vn] = s;
    }
    return si[s];
}

int StringToInt(string s) {
    int flag = 1, i = 0;
    if (s[0] == '-') {
        flag = -1;
        i = 1;
    }
    int len = s.length(), x = 0;
    for (i; i < len; i++) {
        x *= 10;
        x += s[i] - '0';
    }
    return x * flag;
}

void Handle(string s) {
    int pos = s.find('+');
    int pos2 = s.find('=');
    string pre = s.substr(0, pos);
    string af = s.substr(pos + 1, pos2 - pos - 1);
    string eq = s.substr(pos2 + 1, s.length() - 1 - pos2);
    int pren = Hash(pre);
    int afn = Hash(af);
    int eqn = StringToInt(eq);
    AddDoubleEdge(pren, afn, eqn);
}

pair<int, int> HandleRes(string s) {
    int pos = s.find('+');
    string pre = s.substr(0, pos);
    string af = s.substr(pos + 1, s.length() - 1- pos);
    int x = -1, y = -1;
    if (si.find(pre) != si.end()) x = si[pre];
    if (si.find(af) != si.end()) y = si[af];
    return make_pair(x, y);
}

void Read() {
    n = in();
    string s;
    for (int i = 0; i < n; i++) {
        cin >> s;
        Handle(s);
    }
}

void Init() {
    vn = 0;
    while (edges.size()) edges.pop_back();
    is.clear();
    si.clear();
    for (int i = 1; i < maxn; i++) {
        while (G[i].size())
            G[i].pop_back();
    }
}

void print_graph() {
    for (int i = 1; i <= vn; i++) {
        cout << is[i] << ": ";
        for (int j = 0; j < G[i].size(); j++) {
            cout << is[edges[G[i][j]].v] << ',' << edges[G[i][j]].w << ' ';
        }
        cout << endl;
    }
}

int BFS(int u, int target) {
    int vis[maxn];
    memset(vis, 0, sizeof(vis));
    queue<pair<int, int>> Q;
    for (int i = 0; i < G[u].size(); i++) {
        Edge e = edges[G[u][i]];
        vis[e.v] = 1;
        Q.push(make_pair(e.v, e.w));
    }
    while (!Q.empty()) {
        pair<int, int> now = Q.front(); Q.pop();
        if (now.first == target) {
            return now.second;
        }
        for (int i = 0; i < G[now.first].size(); i++) {
            Edge e = edges[G[now.first][i]];
            pair<int, int> next = make_pair(e.v, e.w);
            for (int j = 0; j < G[next.first].size(); j++) {
                Edge ee = edges[G[next.first][j]];
                if (!vis[ee.v]) {
                    vis[ee.v] = 1;
                    Q.push(make_pair(ee.v, now.second - next.second + ee.w));
                }
            }
        }
    }
    return -1;
}

void Solve() {
    m = in();
    while (m--) {
        string s;
        cin >> s;
        pair<int, int> pii = HandleRes(s);
        if (pii.first == -1 || pii.second == -1) continue;
        int t = BFS(pii.first, pii.second);
        if (t != -1) {
            cout << is[pii.first] << '+' << is[pii.second] << '=' << t << endl;
        } else {
            int a = BFS(pii.first, pii.first);
            int b = BFS(pii.second, pii.second);
            if (a != -1 && b != -1)
                cout << is[pii.first] << '+' << is[pii.second] << '=' << (a + b) / 2 << endl;
        }
    }
}

int main() {
    int T = in(), kase = 0;
    while (T--) {
        Init();
        Read();
        printf("Case #%d:\n", ++kase);
        Solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值