hihoCoder- 403 Forbidden(Trie树问题 C解决)

题目1 : 403 Forbidden
时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

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.
输入

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.
输出

For each request output “YES” or “NO” according to whether it is allowed.
样例输入

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

样例输出

YES
YES
NO
YES
NO

每个IP地址可以看作是一个长度32的01字符串。同理每个子网掩码(address/mask)可以看作一个长度不超过32的01字符串。

例如对于样例

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

对应的01串为:

allow 00000001 00000010 00000011 000001
deny 00000001 00000001 00000001 00000001
allow 01111111 00000000 00000000 00000001
allow 011
deny (空串)

然后对于每一个要处理的IP,我们需要判断它是不是有一个前缀同某一个规则匹配。

例如IP1.2.3.4,它的01串是00000001 00000010 00000011 00000100,第一条规则恰好是它的前缀。所以1.2.3.4会匹配allow 1.2.3.4/30,会被允许访问。当然一个IP有可能同时匹配多条规则,比如1.2.3.4也会匹配到deny 0.0.0.0/0,这时按照题意以输入中靠前的规则为准。

对于这样的前缀匹配问题,我们当然首先会想到用trie树解决啦!

对于每一条规则,我们把它的01串插入到trie树中,同时在终结点记录这条规则是allow还是deny,以及规则的序号是多少。

对于每一条要处理的IP,我们在trie树中查找这个01串。沿途经过的终结点都是匹配上的规则。我们只需要在这些终结点中找到序号最小的规则即可。

总复杂度是O(32(N+M))的。
《hihoCoder- 403 Forbidden(Trie树问题 C解决)》

#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
const int INF = 100003;
char ch1[INF][23];
char ch2[INF];
const int INTMAX = 2147483647;
struct TrieNode {
    int num;  //记录规则序号
    TrieNode *next[3];
    bool exist;
};

TrieNode * create() {
  TrieNode* node = (TrieNode *)malloc(sizeof(TrieNode));
  node -> num = INTMAX;
  node -> exist = false;
  memset(node -> next, 0, sizeof(node -> next));
  return node;
}

void Trie_insert(TrieNode * root, char *word, int num) {
    TrieNode * node = root;

    char *p = word;
    int id;
    while(*p) {
        id = *p - '0';
        if(node -> next[id] == NULL) {
            node -> next[id] = create();
        }
        node = node -> next[id];
        ++p;
        if(node -> exist) {
            return ;
        }
    }
    node -> exist = true;
    node -> num = num;
}

int TrieSearch(TrieNode *root, char *word) {
    TrieNode* node = root;
    char *p = word;
    int id;
    int seq = INTMAX;
    while(*p) {
        if(node -> exist) {
            seq = min(node -> num, seq);
        }
        id = (*p) - '0';
        node = node -> next[id];
        if(node == NULL) {
            return seq;
        }
        p++;
    }
    if(node -> exist) {
        seq = min(node -> num, seq);
    }
    return seq;
}

void dfs(char *rtn, int n, int len) {
    if(n / 2 > 0) {
        dfs(rtn, n / 2, len + 1);
        rtn[8 - len] = n % 2 + 48;
    } else {
        for(int i = 0; i < 8 - len; i++) {
            rtn[i] = '0';
        }
        rtn[8 - len] = n + 48;
    }
    rtn[8] = '\0';
    return ;
}
char* convert(char *ip) {
    char *rtn = new char[100], *newHead = ip;
    int total = 0;
    char *p = strchr(ip, '.');
    rtn[0] = '\0';
    while(p != NULL) {
        int digit = 0;

        for(; ip < p; ip++) {
            digit = digit * 10 + (*ip) - 48;
        }
        char num[8];
        dfs(num, digit, 1);
        num[8] = '\0';
        strcat(rtn, num);
        ip += 1;
        if(strchr(p + 1, '.') != NULL) {
            p = strchr(p + 1, '.');
        } else if(strchr(p + 1, '/') != NULL) {
            p = strchr(p + 1, '/');
        } else if(strchr(p + 1, '\0') != NULL){
            if((*p) == '\0' || (*p) == '/') {
                break;
            }
            p = strchr(p + 1, '\0');
        } else {
            break;
        }
    }
    int digit = 0;
    if(strchr(newHead, '/') != NULL) {
        char* p = strchr(ip, '\0');
        for(; ip < p; ip++) {
            digit = digit * 10 + (*ip) - 48;
        }
        rtn[digit] = '\0';
    } else {
        rtn[32] = '\0';
    }
    return rtn;
}

int main() {

    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        TrieNode* root = create();
        for(int i = 0; i < n; i++) {
            scanf("%s %s", ch1[i], ch2);
            Trie_insert(root, convert(ch2), i);

        }
        for(int i = 0; i < m; i++) {
            char req[33];
            scanf("%s", req);
            int seq = TrieSearch(root, convert(req));
            if(seq == INTMAX) {
                printf("YES\n");
            } else {
                printf("%s\n", strcmp(ch1[seq], "allow") == 0 ? "YES" : "NO");
            }
        }
    }

    return 0;
}
/* 3 35 deny 123.0.0.0/3 allow 127.0.0.1 allow 123.234.12.23/3 123.0.0.0 */
    原文作者:Trie树
    原文地址: https://blog.csdn.net/lsgqjh/article/details/71557035
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞