集合

并查集可以很好的把从属关系表达出来

int fa[MAXN]  
void init(int n)
{
  for(int i=1;i<=n;i++)
  {
  fa[i]=i;
  }
}
void find(int i)
{
 if(fa[i]==i)
 return fa[i];
 else
 {fa[i]=find(fa[i])
 return fa[i];
 }
 )
 void unionn(int i,int j)
 {
 int i_fa=find(i);
 int i_fb=find(j);
 fa[i_fa]=i_fb;
 }
 

P1551
其实就是每一次都unionn,然后下面就是查询,模板题就是了

#include<bits/stdc++.h>
using namespace std;
int a,b,c,d,f[10008];
int fd(int x)
{
	if(f[x]==x)
	return x;
	else
	return  x=fd(f[x]);
}
void hb(int a,int b)
{
	f[fd(b)]=fd(a);//很直接的简化
	return;}
int main()
{
	int n,m,p;
	cin>>n>>m>>p;
	for(int i=1;i<=n;i++)
	{
		f[i]=i;
	}
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b;
		hb(a,b);
	}
	for(int i=1;i<=p;i++)
	{
		cin>>c>>d;
		if(fd(c)==fd(d))
		cout<<"Yes"<<endl;
		else
		cout<<"No"<<endl;
	}
	return 0;
}

P1536
每一条都联通,就是没有没被包含进去的城市,先把他们连起来,然后看有几个独立的组总结点,再把祖宗结点连起来

#include<iostream>
using namespace std;
int sum,fa[1001],ans;
void init(int a)
{
	for(int i=1;i<=a;i++)
	{
		fa[i]=i;
	}
}
int find(int a)
{
	if(a==fa[a])
	return a;
	else
	{
		fa[a]=find(fa[a]);
		return fa[a];
	}
	
}
void unionn(int i,int j)
{
	int la=find(i);
	int lb=find(j);
	fa[la]=lb;

}
int main()
{
	int b,a,x,y;
	while(1)
	{
		ans=0;
	cin>>a;
	if(a=='0') return 0;///结尾!
	cin>>b;
	init(a);//咱们先初始化,千万不要忘记
	for(int i=1;i<=b;i++)
	{
		cin>>x>>y;
		unionn(x,y);
	}
	for(int i=1;i<=a;i++)
	{
		if(find(i)==i)//不忘初心的祖宗结点
		{
			ans++;
		}
	}
	cout<<ans-1<<endl;
	}

	return 0;
}

P3370
哈希,一个我一直没有get的东西
一轮输入,二轮两重循环
查找,相同的话就把两个人都打上标记,最后没有打上标记的就是了
数组里面也是可以存字符串的,比较方式应该是逐位比较ascll码

#include<bits/stdc++.h>
  using namespace std;
  string s[1000000];
  bool flag[10000000];
  long long ans;
 
  int main()
  {
  	int n;
  	cin>>n;
  	for(int i=1;i<=n;i++)
	  {
	  	cin>>s[i];
	   } 
  	for(int i=1;i<=n;i++)
  	{
  		if(flag[i]==1)
  		{
  			ans++;
  			continue;
		  }
		  for(int j=i+1;j<=n;j++)
		  {
		  	if(s[j]==s[i])
		  	{
		  		flag[j]=1;
		  		flag[i]=1;
			  }
		  }
	  }
	  cout<<n-ans;
	}  
 

set的写法
去重的好帮手

#include<bits/stdc++.h>
using namespace std;
set<string> a;
int main()
{
    string p;
    int n,i;
    cin>>n;
    for(i=0;i<n;i++)
    {
    	cin>>p;
    	a.insert(p);
	}
	cout<<a.size();
}

欣赏有一些大佬们用纯正哈希编写的

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef unsigned long long ull;
ull base=131;
ull a[10010];
char s[10010];
int n,ans=1;
int prime=233317; 
ull mod=212370440130137957ll;
ull hashe(char s[])
{
 int len=strlen(s);
 ull ans=0;
 for (int i=0;i<len;i++)
 ans=(ans*base+(ull)s[i])%mod+prime;
 return ans;
}
int main()
{
 scanf("%d",&n);
 for(int i=1;i<=n;i++)
 {
 	scanf("%s",s);
 	a[i]=hashe(s);
 }
 sort(a+1,a+n+1);
 for(int i=1;i<n;i++)
 {
 	if(a[i]!=a[i+1])
 	ans++;
 }
 printf("%d",ans);
} 

进制哈希:给出一个固定的进制base,将一个串上的每一个元素看作一个base进制的数字,那么这个数就是这个串的哈希,通过比较每个串的哈希,判断是否相同
ans=(ans*base+(ull)s[i[)%mod+prime

无错哈希

for(int i=1;i<=m;i++)//m个串
{
cin>>str;//下一行的check为bool型 
while(check[hash(str)])hash[i]+=19260817;
hash[i]+= hash(str) ;
}

双哈希

include <cstdio>
#include <cstring>
#include <algorithm>
#define ll int
#define inf 1<<30
#define mt(x,y) memset(x,y,sizeof(x))
#define il inline 
#define ull unsigned long long
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll abs(ll x){return x>0?x:-x;}
il ll swap(ll x,ll y){ll t=x;x=y;y=t;}
il void read(ll &x){
    x=0;ll f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
using namespace std;
#define N 10001
#define base 233
ull mod1=212370440130137957ll;
ull mod2=inf;
ll n;
char a[N];
struct node{ll x,y;}f[N];
il ull hash1(char s[]){
    ll ans=0,len=strlen(s);
    for(ll i=0;i<len;i++){
        ans=(base*ans+(ull)s[i])%mod1;
    }
    return ans;
}
il ull hash2(char s[]){
	ll ans=0,len=strlen(s);
	for(ll i=0;i<len;i++){
		ans=(base*ans+(ull)s[i])%mod2;
	}
	return ans;
}
il bool cmp1(node a,node b){return a.x<b.x;}
il bool cmp2(node a,node b){return a.y<b.y;}
int main(){
    read(n);
    for(ll i=1;i<=n;i++){
        scanf("%s",a);
        f[i].x=hash1(a);
        f[i].y=hash2(a);
    }
    sort(f+1,f+n+1,cmp1);sort(f+1,f+n+1,cmp2);
	ll ans=1;
    for(ll i=1;i<n;i++){
        if(f[i].x!=f[i+1].x||f[i].y!=f[i+1].y)ans++;
    }
    printf("%d\n",ans);
    return 0;
}

P3405
其实就是匹配,每一头牛都有对应两个,然后可以编成数字,有点哈希的味道,然后存进去,然后有点map的感觉,此基础上变化成另外一个对应的,然后统计他的值

#include<iostream>
 using namespace std;
 int n,x,y,ans,city[800][800];
 int main()
 {
 	string a,b;
 	cin>>n;
 	for(int i=0;i<n;i++)
 	{
 		cin>>a>>b;
 		x=(a[0]-'A')*26+a[1]-'A';
 		y=(b[0]-'A')*26+b[1]-'A';
 		if(x!=y)
 		{
 			city[x][y]++;
 			ans+=city[y][x];
		 }
	 }
	 cout<<ans;
	 return 0;
  } 
 
 #include<iostream>
  #include<cstdio>
  #include<cmath>
  #include<algorithm>
  #include<cstring>
  #include<map>
  #include<vector>
  #include<queue>
  #include<stack>
  #include<set>
  #define fore(i,a,b) for(register int i=a;i<=b;i++)
  #define foru(i,a,b) for(register int i=a;i<b;i++)
  #define ford(i,a,b) for(register int i=a;i>=b;i--)
  #define IGNB std::ios::sync_with_stdio(false);
  #define ll long long
  #define INF 0x3fffffff
  using namespace std;
  map<int,map<int,int> >m;
  string x,y;
  int main(){
      IGNB;
      int n,cnt=0;
      cin>>n;
      fore(i,1,n){
          cin>>x>>y;
          int x1=x[0]*100+x[1];
          int y1=y[0]*100+y[1];
          if(x1!=y1){
              cnt+=m[y1][x1];
              m[x1][y1]++;
          }	
      }
      cout<<cnt;
      return 0;
  }

#include<bits/stdc++.h>
using namespace std;
map<int,int>mmp[100005];
int n,ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        string a,b;
        cin>>a>>b;
        int A=a[0]*26+a[1];
        int B=b[0]*26+b[1];
        ans+=mmp[B][A];
        if(A==B)ans-=mmp[A][B];
        mmp[A][B]++;
    }
    printf("%d",ans);
    return 0;
}

P5266

#include<iostream>
#include<cstring>
#include<map>
using namespace std;
map <string,int> a;
int main(){
    int n;
    cin>>n; 
    for(int i=1;i<=n;i++){
    	int op;
    	string name; 
    	cin>>op; 
    	if(op!=4) 
    	cin>>name;
    	switch(op){ 
    		case 1: 
	   		int score;
    		cin>>score;
    		a[name]=score;//桶思想
    		cout<<"OK\n"; 
    		break;   
    		case 2:
    		if(a.count(name)) 
    		cout<<a[name]<<endl;
    		else cout<<"Not found\n";
    		break;   
    		case 3: 
    		if(a.count(name)){ 
    		a.erase(name); 
			cout<<"Deleted successfully\n"; 
    	    }
    		else cout<<"Not found\n"; 
    		break;  
    		case 4: 
    		cout<<a.size()<<endl; 
		}
	}
	return 0;
}

插入修改:map 一一对应
查询:a.count(name)
删除:先查询后删除,a.erase(name)

关于map


// 定义一个map对象
map<int, string> mapStudent;
 
// 第一种 用insert函數插入pair
mapStudent.insert(pair<int, string>(000, "student_zero"));
 
// 第二种 用insert函数插入value_type数据
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
 
// 第三种 用"array"方式插入
mapStudent[123] = "student_first";
mapStudent[456] = "student_second";
以上三种用法,虽然都可以实现数据的插入,但是它们是有区区别的,当然了第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是不能在插入数据的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值,用程序说明如下:

// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
iter = mapStudent.find("123");
 
if(iter != mapStudent.end())
       cout<<"Find, the value is"<<iter->second<<endl;
else
   cout<<"Do not Find"<<endl;
//迭代器刪除
iter = mapStudent.find("123");
mapStudent.erase(iter);
 
//用关键字刪除
int n = mapStudent.erase("123"); //如果刪除了會返回1,否則返回0
 
//用迭代器范围刪除 : 把整个map清空
mapStudent.erase(mapStudent.begin(), mapStudent.end());
//等同于mapStudent.clear()
begin()         返回指向map头部的迭代器

     clear()        删除所有元素

     count()         返回指定元素出现的次数, (帮助评论区理解: 因为key值不会重复,所以只能是1 or 0)

     empty()         如果map为空则返回true

     end()           返回指向map末尾的迭代器

     equal_range()   返回特殊条目的迭代器对

     erase()         删除一个元素

     find()          查找一个元素

     get_allocator() 返回map的配置器

     insert()        插入元素

     key_comp()      返回比较元素key的函数

     lower_bound()   返回键值>=给定元素的第一个位置

     max_size()      返回可以容纳的最大元素个数

     rbegin()        返回一个指向map尾部的逆向迭代器

     rend()          返回一个指向map头部的逆向迭代器

     size()          返回map中元素的个数

     swap()           交换两个map

     upper_bound()    返回键值>给定元素的第一个位置

     value_comp()     返回比较元素value的函数

P1102

#include<bits/stdc++.h>
using namespace std;
map<string,set<int> > m;
set<int>::iterator iter;
int main()
{
	int l;
	cin>>l;
	for(int i=1;i<=l;i++)
	{
		int h;
		cin>>h;
		for(int j=1;j<=h;j++)
		{
			 string s;
	        cin>>s;
	        m[s].insert(i);
		}
	}
	int p;
	cin>>p;
	for(int i=1;i<=p;i++)
	{
		string k;
		cin>>k;
		if(m.count(k))
		for(iter=m[k].begin();iter!=m[k].end();iter++)
		cout<<*iter<<" ";
		cout<<endl;
	}
 } 

几句话,用string输入,存入m[s].insert(i)m,为什么这里不能覆盖,因为pair的第二个是set<,毕竟从小到大1,然后通过查询来遍历

p2814

#include<iostream>
#include<map> 
using namespace std;
string s,s1;
map<string,string>p;
string find(string x)
{
	if(x!=p[x])
	p[x]=find(p[x]);
	return p[x];
}
int main()
{
	char ch;
	cin>>ch;
	while(ch!='$')
	{
		cin>>s;
		if(ch=='#')
		{
			s1=s;///把祖先存在这里 
			if(p[s]=="")p[s]=s;
		}
		else if(ch=='+')
		p[s]=s1;
		else cout<<s<<' '<<find(s)<<endl;
		cin>>ch; 
	 } 
	 return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值