hash 亂搞=。=

題目鏈接:http://acm.neu.edu.cn/hustoj/problem.php?id=1588

題意:給出路由器的轉發表,然後對於每組詢問,輸出應該從哪個端口出去。需要滿足最長掩碼匹配,如果有多個匹配,輸出端口最小的那個

思路:開始用的map,無限T。賽後亂搞的hash。。hash也是亂搞的,衝突了就存到數組的下一個位置=。=

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
    ll son;
    int port;
};
const int mod = 109987;
Node node[33][110000];
bool vis[33][110000];
void hashh(int mask,ll a,int port){
    int tmp = a%mod;
    while(1){//cout<<tmp<<endl;
        if(vis[mask][tmp] == 0){
            vis[mask][tmp] = 1;
            node[mask][tmp].son = a;
            node[mask][tmp].port = port;
            break;
        }
        else if(node[mask][tmp].son == a){
            node[mask][tmp].port = min(node[mask][tmp].port,port);
            break;
        }
        tmp ++;
        if(tmp >= mod)tmp -= mod;
    }
}
void find(ll tmp){
    for(int i = 32;i >= 0;i --){
        ll mask = ((1LL<<i)-1)*(1LL<<(32-i));
        ll now = (tmp&mask);
        int ff = now%mod;
        while(1){
            if(vis[i][ff] == 0)break;
            else if(node[i][ff].son == now){
                printf("%d\n",node[i][ff].port);
                return;
            }
            ff ++;
            if(ff >= mod)ff -=mod;
        }
    }
    puts("65535");
}
int main(){
    int T;
    scanf("%d",&T);
    while(T --){
        memset(vis,0,sizeof(vis));
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 0;i < n;i ++){
            int a,b,c,d,mask,port;
            scanf("%d.%d.%d.%d/%d %d",&a,&b,&c,&d,&mask,&port);
            ll tmp = ((a*256+b)*256+c)*256+(ll)d;
            ll mm = ((1LL<<mask)-1)*(1LL<<(32-mask));
            tmp = (tmp&mm);//cout<<tmp<<endl;
            hashh(mask,tmp,port);//cout<<hh<<endl;
        }
        for(int i = 0;i < m;i ++){
            int a,b,c,d;
            scanf("%d.%d.%d.%d",&a,&b,&c,&d);
            ll tmp = ((a*256+b)*256+c)*256+(ll)d;
            find(tmp);
        }
    }
    return 0;
}

這是寫的第一個代碼。。雖然過了,不過感覺有點不爽,於是又接着各種改,於是又TTTTT。。
然後下面的是第二份代碼(雖然沒有上個慢,不過感覺下面的代碼更通用一點?
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
    ll son;
    int port,mask;
};
const int mod = 99991;
vector<Node>vv[mod+1];
void hashh(int mask,ll a,int port){
    int tmp = a%mod;
    int siz = vv[tmp].size();
    for(int i = 0;i < siz;i ++){
    	if(vv[tmp][i].son == a&&vv[tmp][i].mask == mask){
    		vv[tmp][i].port = min(vv[tmp][i].port,port);
    		return ;
    	}
    }
    Node t;
    t.son = a;
    t.port = port;
    t.mask = mask;
    vv[tmp].push_back(t);
}
void find(ll tmp){
    for(int i = 32;i >= 0;i --){
        ll mask = ((1LL<<i)-1)*(1LL<<(32-i));
        ll now = (tmp&mask);
        int ff = now%mod;
        int siz = vv[ff].size();
        for(int j = 0;j < siz;j ++){
        	if(vv[ff][j].mask == i&&vv[ff][j].son == now){
        		printf("%d\n",vv[ff][j].port);
        		return ;
        	}
        }
    }
    puts("65535");
}
int main(){
    int T;
    scanf("%d",&T);
    while(T --){
        for(int i = 0;i < mod;i ++)vv[i].clear();
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 0;i < n;i ++){
            int a,b,c,d,mask,port;
            scanf("%d.%d.%d.%d/%d %d",&a,&b,&c,&d,&mask,&port);
            ll tmp = ((a*256+b)*256+c)*256+(ll)d;
            ll mm = ((1LL<<mask)-1)*(1LL<<(32-mask));
            tmp = (tmp&mm);//cout<<tmp<<endl;
            hashh(mask,tmp,port);//cout<<hh<<endl;
        }
        for(int i = 0;i < m;i ++){
            int a,b,c,d;
            scanf("%d.%d.%d.%d",&a,&b,&c,&d);
            ll tmp = ((a*256+b)*256+c)*256+(ll)d;
            find(tmp);
        }
    }
    return 0;
}

這裏用的mod 是99991,開始用的mod比較大直接就超時了,估計是因爲每組case的時候都需要清空,如果mod太大的話會就會浪太多時間,所以還是得視情況YY,估計做題做多了就能有感覺了吧= 。=

*************************************************************************

然後是第二道題

鏈接:http://poj.org/problem?id=3349

題意:給n個雪花,雪花由六個數字構成,問有沒有兩個一樣的雪花。兩個雪花是一樣的需要滿足:假如a保持不動,那麼b從某個點順時針或逆時針轉動,能找到一種情況滿足6個數字均相等

思路:直接把6個數字相加作爲hash的key值,然後正常hash亂搞,最後3700+ms水過= =,還是對效率不滿意,於是接着亂搞,又T了。。。於是就暫時沒有更快的代碼。。status裏面那些跑了300+ms的都是怎麼搞的= =,太牛逼了

代碼:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a));
const int maxn = 100010;
int n;
struct Node{
	int nn[6];
};
vector<Node>tt[maxn];
bool deng(int *a,int *b){
	for(int i = 0;i < 6;i ++){
		bool dd = 1;
		for(int j = 0;j < 6;j ++)
			if(a[j] != b[(i+j)%6]){dd = 0;break;}
		if(dd)return 1;
	}
	for(int i = 0;i < 6;i ++){
		bool dd = 1;
		for(int j = 0;j < 6;j ++)
			if(a[j] != b[(i-j + 6)%6]){dd = 0;break;}
		if(dd)return 1;
	}
	return 0;
}
int a[6];
bool find(){
	int sum = 0;
	for(int i = 0;i < 6;i ++){
		sum += a[i];
	}//cout<<sum<<endl;
	sum %= maxn;
	int siz = tt[sum].size();
	for(int i = 0;i < siz;i ++){
		if(deng(a,tt[sum][i].nn))return 1;
	}
	Node tmp;
	for(int i = 0;i < 6;i ++)
		tmp.nn[i] = a[i];
	tt[sum].push_back(tmp);
	return 0;
}
int main(){
	while(~ scanf("%d",&n)){
		for(int i = 0;i < maxn;i ++)
			tt[i].clear();
		bool have = 0;
		for(int i = 0;i < n;i ++){
			for(int j = 0;j < 6;j ++)
				scanf("%d",&a[j]);
			have = find();//cout<<have<<endl;
			if(have){
				for(int j = i+1;j < n;j ++){
					int b;
					for(int jj = 0;jj < 6;jj ++)
						scanf("%d",&b);
				}
				break;
			}
		}
		if(have)puts("Twin snowflakes found.");
		else puts("No two snowflakes are alike.");
	}
	return 0;
}


然後開始搞第三題:

鏈接:http://poj.org/problem?id=3349

題意:給出n個奶牛,奶牛擁有k種屬性,每個奶牛的屬性用十進制表示,換算成二進制就是具體的各個屬性是否擁有。現在要找到一個最大的區間,這個區間中,如果將奶牛的屬性用二進制表示,對於任意的兩個屬性A,B,擁有A屬性的奶牛的個數和B是一樣的。

思路:開始讀錯題,異或亂搞,發現不會(按照我理解的題意)。然後百度題解,才理解了題意。。解題思路還是挺巧妙地,首先維護一個從第一個奶牛到當前奶牛的各個屬性的和,然後用其他的屬性分別減去第一個屬性,如果某個區間滿足題目要求,那麼這個區間的兩個頂點經過之前的操作所形成的數組值應該是相同的(因爲每個屬性都增加了相同的個數),於是就要找到最遠的兩個一樣的數組,用數組的和做爲key,亂搞了一發hash。。

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 999983;
struct Node{
	int nn[31];
	int id;
};
int ans;
int n,k;
vector<Node>vv[maxn];
void has(Node now){
	unsigned int sum = 0;
	for(int i = 0;i < k;i ++){
		sum += now.nn[i];
	}
	sum = sum % maxn;//cout<<sum<<"aa"<<endl;
	int siz = vv[sum].size();
	for(int i = 0;i < siz;i ++){
		bool deng = 1;
		for(int j = 0;j < k;j ++)
			if(now.nn[j] != vv[sum][i].nn[j]){deng = 0;break;}//cout<<"aaaaaaa";
		if(deng){ans = max(ans,now.id - vv[sum][i].id);return;}
	}
	vv[sum].push_back(now);
}
int main(){
	while(~scanf("%d%d",&n,&k)){
		ans = 0;
		for(int i = 0;i < maxn;i ++)
			vv[i].clear();
		Node in;
		Node last;
		for(int i = 0;i < k;i ++)last.nn[i] = 0;
		last.id = 0;
		has(last);
		for(int i = 1;i <= n;i ++){
			int a;
			scanf("%d",&a);
			for(int j = 0;j < k;j ++){
				last.nn[j] += (a&1);
				a >>= 1;
				in.nn[j] = last.nn[j] - last.nn[0];
			}
			in.id = i;
			has(in);
		}
		cout<<ans<<endl;
	}
	return 0;
}


/*************************************************************************************************************

亂入一個字符串hash 的代碼(雖然之前教主好像講過。。

// BKDR Hash Function 
unsigned int BKDRHash(char*str)
{
    unsigned int seed=131 ;// 31 131 1313 13131 131313 etc.. 
    unsigned int hash=0 ;
    
    while(*str)
    {
        hash=hash*seed+(*str++);
    }
    return(hash % M);
}


然後根據上面的字符串的hash過了一個水題= =

鏈接:http://poj.org/problem?id=2503

思路:先給一堆成對字符串,然後輸入一個空行,然後再給一對字符串,問這個字符串(開始是後面的)對應的那個字符串是什麼,就是很簡單的對應

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
struct Node{
	char s[12];
	char ans[12];
};
const int mod = 99991;
vector<Node>vv[mod];
unsigned int hh(char a[]){
	unsigned int ans = 0;
	unsigned int seed = 31;
	while(*a){
		ans = ans*seed + (*a ++);
	}//cout<<ans%mod<<endl;
	return ans % mod;
}
void has(char b[],char a[]){
	unsigned int nn = hh(b);
	Node tmp;
	strcpy(tmp.s,b);
	strcpy(tmp.ans,a);
	vv[nn].push_back(tmp);
}
void find(char s[]){
	unsigned int nn = hh(s);
	int siz = vv[nn].size();
	for(int i = 0;i < siz;i ++){
		if(strcmp(vv[nn][i].s,s) == 0){
			puts(vv[nn][i].ans);
			return ;
		}
	}
	puts("eh");
}
int main(){
    char s[100];
    char a[100],b[100];
    while(gets(s)){
    	if(strlen(s) == 0)break;
    	int l = strlen(s);
    	for(int i = 0;i < l;i ++){
    		if(s[i] == ' '){
    			a[i] = '\0';
    			for(int j = i+1;j < l;j ++)
    				b[j-i-1] = s[j];
    			b[l-i-1] = '\0';
    			break;
    		}
    		a[i] = s[i];
    	}
    	has(b,a);
    }
    while(gets(s)){
    	find(s);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章