Microsoft 2016 Campus Hiring Contest - April - 1289 : 403 Forbidden

Description
Little Hi runs a web server. Sometimes he has to deny access from a certain set of malicious IP addresses while his friends are still allow to access his server. To do this he writes N rules in the configuration file which look like:
allow 1.2.3.4/30
deny 1.1.1.1
allow 127.0.0.1
allow 123.234.12.23/3
deny 0.0.0.0/0
Each rule is in the form: allow | deny address or allow | deny address/mask.
When there comes a request, the rules are checked in sequence until the first match is found. If no rule is matched the request will be allowed. Rule and request are matched if the request address is the same as the rule address or they share the same first mask digits when both written as 32bit binary number.
For example IP "1.2.3.4" matches rule "allow 1.2.3.4" because the addresses are the same. And IP "128.127.8.125" matches rule "deny 128.127.4.100/20" because 10000000011111110000010001100100 (128.127.4.100 as binary number) shares the first 20 (mask) digits with 10000000011111110000100001111101 (128.127.8.125 as binary number).
Now comes M access requests. Given their IP addresses, your task is to find out which ones are allowed and which ones are denied.
Input
Line 1: two integers N and M.
Line 2-N+1: one rule on each line.
Line N+2-N+M+1: one IP address on each line.
All addresses are IPv4 addresses(0.0.0.0 - 255.255.255.255). 0 <= mask <= 32.
For 40% of the data: 1 <= N, M <= 1000.
For 100% of the data: 1 <= N, M <= 100000.
Output
For each request output "YES" or "NO" according to whether it is allowed.
Sample Input
5 5
allow 1.2.3.4/30
deny 1.1.1.1
allow 127.0.0.1
allow 123.234.12.23/3
deny 0.0.0.0/0
1.2.3.4
1.2.3.5
1.1.1.1
100.100.100.100
219.142.53.100
Sample Output
YES
YES
NO
YES
NO

思路分析
这是这个problem set 4道题的第2道,我以为是一道简单题,即顺序匹配各条规则,然而超时了!
到网上查了思路,是用Trie树来做。需要注意的是,代表规则末尾的节点不仅要记录规则是allow/deny,还需要记录这是第几条规则(index),在匹配阶段,要找到所有匹配的情况,取index最小的匹配。通过建Trie树,每次匹配都是O(1)的!因为树的深度最多是32层,是固定的!确实比暴力匹配好到不知道哪里去了!
不能小看微软的题啊!哪有那么多简单题!总结的经验是,第一题不要想难了,从第二题开始就不要想简单了!

AC代码

//
// Created by Xue Li on 2017/3/21.
//

#include 
#include 

using namespace std;
const int MAX = 100000;

struct Node{
    string state = "";
    Node *left = NULL;
    Node *right = NULL;
    int index;
};

void insertRule(char *s, Node *head, int index);
unsigned getIP(char *s, int left, int right);
void check(Node *head, unsigned ip);
void forbidden();

int main(){
    forbidden();
    return 0;
}

void forbidden(){
    int n, m;
    cin >> n >> m;
    cin.ignore();
    char s[30];
    Node *head = new Node;
    for (int i = 0; i < n; i++){
        cin.getline(s, 30);
        insertRule(s, head, i);
    }

    for (int i = 0; i < m ; i++){
        cin.getline(s, 20);
        int tail = 0;
        while (s[tail] != '\0'){
            tail++;
        }
        unsigned ip = getIP(s, 0, tail);
        check(head, ip);
    }
}

void insertRule(char *s, Node *head, int index){
    string rst;
    int left, i;
    int mask = 32;
    if (s[0] == 'd'){
        rst = "NO";
        left = 5;
    }
    else{
        rst = "YES";
        left = 6;
    }
    i = left;
    while (s[i] != '/' and s[i] != '\0'){
        i+=1;
    }
    unsigned ip = getIP(s, left, i);
    if (s[i] == '/'){
        i += 1;
        mask = 0;
        while (s[i] != '\0'){
            mask = mask * 10 + (s[i] - '0');
            i++;
        }
    }
    Node *p = head;
//    用digit这个变量,来和ip的相与,能够得到ip的每一位!
    unsigned digit = (unsigned)1 << 31;
    for (int i = 0; i < mask; i++){
        if ((ip & digit) == 0){
            if (p->left == NULL){
                Node* child = new Node;
                p->left = child;
            }
            p = p->left;
        }
        else{
            if (p->right == NULL){
                Node* child = new Node;
                p->right = child;
            }
            p = p->right;
        }
        digit >>= 1;
    }
    if (p->state == ""){
        p->state = rst;
        p->index = index;
    }
}

void check(Node *head, unsigned ip){
    unsigned digit = (unsigned)1 << 31;
    int index = MAX + 1;
    string state = "YES";
    Node *p = head;
    if (p->state != "" && p->index < index) {
        index = p->index;
        state = p->state;
    }
    for (int i = 0; i < 32; i++){
        if ((ip & digit) == 0){
            p = p->left;
            if (p == NULL)
                break;
        }
        else{
            p = p->right;
            if (p == NULL)
                break;
        }
        if (p->state != "" && p->index < index) {
            index = p->index;
            state = p->state;
        }
        digit >>= 1;
    }
    cout << state << endl;
}

unsigned getIP(char *s, int left, int right){
    int i = left;
    unsigned ip = 0;
    int d = 0;
    while (i < right){
        if (s[i] == '.'){
            ip = ip << 8;
            ip += d;
            d = 0;
        }
        else{
            d = d * 10 + (s[i] - '0');
        }
        i += 1;
    }
    ip = ip << 8;
    ip += d;
    return ip;
}

你可能感兴趣的:(Microsoft 2016 Campus Hiring Contest - April - 1289 : 403 Forbidden)