并查集可以很好的把从属关系表达出来
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;
}