<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">今年微软笔试题,http://hihocoder.com/problemset/problem/1289,403 Forbidden,第一来我一看到题目想都没想直接用暴力搜索,最后也没调通,后来仔细想了想有很多要注意的,尤其是当有多个匹配的时候,输出索引最小的那个rule,这点很重要。</span>
后来想想可以用字典树解决,知识由于考试时间限制,trie树写的不熟练,现在重新写一遍,上代码:
#include<iostream>
using namespace std;
//先写一个用静态链表(即模拟指针实现的trie树)
struct trienode
{
int index;
int next[2];
trienode()
{
index=-1;
next[0]=next[1]=-1;
}
};
int cnt=0;
const int Nmax=1e5+5;
const int maxlen=32;
trienode triegraph[Nmax*maxlen];
bool isAllow[Nmax*maxlen];
void addnode(unsigned int IPnum, bool flagallow, int index, int masknum)
{
int now=0;
bool k;
for (int i=masknum-1;i>=0;--i)
{
k=(IPnum&(1<<i));
if (triegraph[now].next[k]==-1)
triegraph[now].next[k]=++cnt;
now=triegraph[now].next[k];
}
if (triegraph[now].index==-1)
{
triegraph[now].index=index;
isAllow[now]=flagallow;
}
}
void query(unsigned int num)
{
int now=0;
bool k;
int v=-1;
bool flagresult;
for (int i=maxlen-1;i>=0;--i)
{
k=(num&(1<<i));
if (triegraph[now].index!=-1)
if (v==-1||v>triegraph[now].index)
{
v=triegraph[now].index;
flagresult=isAllow[now];
}
if (triegraph[now].next[k]==-1)
break;
now=triegraph[now].next[k];
}
if (triegraph[now].index!=-1)
{
if (v==-1||v>triegraph[now].index)
{
v=triegraph[now].index;
flagresult=isAllow[now];
}
}
if (v==-1)
cout<<"YES"<<endl;
else
cout<<(flagresult==true?"YES":"NO")<<endl;
}
int main()
{
int N,M;
scanf("%d%d",&N,&M);
//add rules
char opt[8],str[20];
bool flagallow=false;
int masknum;
unsigned int a,b,c,d;
unsigned int IPnum;
for (int i=0;i<N;++i)
{
scanf("%s%s",opt,str);
if (opt[0]=='a')
flagallow=true;
else
flagallow=false;
int len=strlen(str);
masknum=-1;
for (int j=0;j<len;++j)
{
if (str[j]=='/')
{
sscanf(str+j+1,"%d",&masknum);
str[j]='\0';
break;
}
}
sscanf(str,"%d.%d.%d.%d",&a,&b,&c,&d);
IPnum=(a<<24)+(b<<16)+(c<<8)+d;
if (masknum!=-1)
IPnum=(IPnum>>(32-masknum));
else
masknum=maxlen;
addnode(IPnum,flagallow,i,masknum);
}
//query IP
for (int i=0;i<M;++i)
{
scanf("%s",str);
sscanf(str,"%d.%d.%d.%d",&a,&b,&c,&d);
IPnum=(a<<24)+(b<<16)+(c<<8)+d;
query(IPnum);
}
return 0;
}
最后把我用暴力搜索的代码贴上,明显TLE啊
#include<iostream>
#include<string>
#include<cstring>
#include<utility>
using namespace std;
const int Nmax=1e5+2;
pair<unsigned int,string> IPset[Nmax];
int IPmask[Nmax];
int countIP=0;
int N,M;
void ipToint(string str,string s)
{
int len=str.size();
unsigned int ans=0;
bool mask=false;
unsigned int ans_dot=0;
int masknum=0;
for (int i=0;i<len;++i)
{
if (mask==false)
{
if (str[i]=='.')
{
ans_dot=ans_dot<<8;
ans_dot+=ans;
ans=0;
}
else if (str[i]=='/')
mask=true;
else
{
unsigned int difchar=str[i]-'0';
ans=ans*10+difchar;
}
}
else
{
int difchar=str[i]-'0';
masknum=masknum*10+difchar;
}
}
ans=(ans_dot<<8)+ans;//注意,位操作运算符的优先级较低
if (!mask)
masknum=-1;
IPset[countIP]=make_pair(ans,s);
IPmask[countIP]=masknum;
countIP++;
}
unsigned int ipToint1(string str)
{
int len=str.size();
unsigned int ans_dot=0;
unsigned int ans=0;
for (int i=0;i<len;++i)
{
if (str[i]=='.')
{
ans_dot=ans_dot<<8;
ans_dot+=ans;
ans=0;
}
else
{
unsigned int difchar=str[i]-'0';
ans=ans*10+difchar;
}
}
ans=(ans_dot<<8)+ans;
return ans;
}
pair<bool,bool> queryIP(unsigned int number)
{
bool yesno=false;
bool found=false;
for (int i=0;i<N;++i)
{
int masknum=IPmask[i];
if (masknum>0)
{
unsigned int ipnum=IPset[i].first;
masknum=32-masknum;
ipnum=ipnum>>masknum;
unsigned int num_temp=number>>masknum;
if (ipnum==num_temp)
{
found=true;
if (IPset[i].second=="allow")
yesno=true;
else
yesno=false;
}
}
else if (masknum==0)
{
found=true;
if (IPset[i].second=="allow")
yesno=true;
else
yesno=false;
}
if (found==true)
break;
}
return make_pair(yesno,found);
}
int main()
{
cin>>N>>M;
for (int i=0;i<N;++i)
{
string s;
cin>>s;
string record;
cin>>record;
ipToint(record,s);
}
for (int i=0;i<M;++i)
{
string record;
cin>>record;
unsigned int ipresult=ipToint1(record);
auto result=queryIP(ipresult);
if (result.second==true&&result.first==true)
cout<<"YES"<<endl;
else if (result.second==true&&result.first==false)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
system("pause");
return 0;
}
PS:sscanf真的很好用,我要好好学学
还有感谢博客http://www.cnblogs.com/andyqsmart/p/5371535.html,从里面我学到很多