1 条题解
-
0
自动搬运
来自洛谷,原作者为

qianxinyu
china-zj-sx||sx鲁迅中学||千许搬运于
2025-08-24 22:28:36,当前版本为作者最后更新于2023-08-28 12:59:51,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Zamjena
题目大意
你有两个数组,数组中有很多数或变量,变量可以赋任意值。你需要判断是否存在一种方法让两个数组中的数两两对应相等。
思路
显然有三种对应关系:
- 当一个常量和一个常量对应时:如果两数相等,它们俩就人畜无害,如果两数不等,那么这两个数组就不可能两两对应相等。
- 当一个变量和一个常量对应时:这个变量没得选,只能跟随常量赋值,但如果这个变量已经和另一个常量对应了,那么就与条件一相似,无解。
- 当一个变量和一个变量对应时:相当于这两个变量同命了,和成一个变量,一个对应了常量,另一个要对应这个常量。
常量的判断简单。 那么任何处理对应呢?
可以想到用并查集将变量合并到常量或另一个变量上。
处理
注:不了解处理中相关算法的可以翻到最底下。
1.输入
考虑到字符串输入,所以使用
scanf("%s",a);进行输入。2.判重
需要判断变量名相同。
很多人会想到用 map 进行处理。
但是,字符串的题就应该用字符串的方法:字典树。字典树数应该更适合做有关前缀的题,但是,这题也可以用上它。它会比 map 更优,因为 map 的单次查询需要 的复杂度,而字典树可以实现 的复杂度。
所以目前我是最优解。
然后可以先特判出数字,对字符串进行标号,让每一个变量都有自己专属的编号。
代码
int trie[500010][30],cnt=1;//注意开10倍数组 int map[500010],cnt2=1010;//我不用万能头,所以可以用这个变量名 int query(char c[]) { int now=1,l=strlen(c); if(c[0]<='9'&&c[0]>='0') { now=0; for(int i=0;i<l;i++) { now*=10; now+=c[i]-'0'; } return now;//数字 } for(int i=0;i<l;i++) { if(!trie[now][c[i]-'a'+1])trie[now][c[i]-'a'+1]=++cnt; now=trie[now][c[i]-'a'+1]; } if(!map[now])map[now]=++cnt2; return map[now];//变量 }并查集
并查集板子很好写。
不过我不喜欢预处理,所以加了一个特判,在不需要处理 时可以写成这样:
if(f[x]==0)return f[x]=x;代码
int find(int x) { if(f[x]==0)return f[x]=x; if(x!=f[x])return f[x]=find(f[x]); return f[x]; } void hb(int x,int y) { int fx=find(x),fy=find(y); if(fx!=fy)f[fy]=fx; }判断
分步处理。注意:优先把变量并进常量,在两个变量之间匹配过常量的最好不被并入其它变量中。
代码
for(int i=1;i<=n;i++) { int x=query(a[i]),y=query(b[i]); if(x==y)continue;//人畜无害 int fx=find(x); if(x<=1000&&y<=1000)//常量不相等 { printf("NE"); return 0; } else if(x<=1000)hb(x,y);//y对应的变量等于x else if(fx<=1000)hb(x,y);//y对应的变量等于x对应的变量匹配的常量 else hb(y,x);//其它情况 } for(int i=1;i<=1000;i++) { if(find(i)!=i)//常量被要求等于另一个常量 { printf("NE"); return 0; } } printf("DA");//全部匹配完整代码
#include<cstdio> #include<cstring> int trie[500010][30],cnt=1; int map[500010],cnt2=1010; int query(char c[]) { int now=1,l=strlen(c); if(c[0]<='9'&&c[0]>='0') { now=0; for(int i=0;i<l;i++) { now*=10; now+=c[i]-'0'; } return now; } for(int i=0;i<l;i++) { if(!trie[now][c[i]-'a'+1])trie[now][c[i]-'a'+1]=++cnt; now=trie[now][c[i]-'a'+1]; } if(!map[now])map[now]=++cnt2; return map[now]; } int f[50010]; int find(int x) { if(f[x]==0)return f[x]=x; if(x!=f[x])return f[x]=find(f[x]); return f[x]; } void hb(int x,int y) { int fx=find(x),fy=find(y); if(fx!=fy)f[fy]=fx; } char a[50010][15],b[50010][15];; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%s",a[i]); for(int i=1;i<=n;i++)scanf("%s",b[i]); for(int i=1;i<=n;i++) { int x=query(a[i]),y=query(b[i]); if(x==y)continue; int fx=find(x); if(x<=1000&&y<=1000) { printf("NE"); return 0; } else if(x<=1000)hb(x,y); else if(fx<=1000)hb(x,y); else hb(y,x); } for(int i=1;i<=1000;i++) { if(find(i)!=i) { printf("NE"); return 0; } } printf("DA"); return 0; }算法了解传送门
并查集
字典树
- 1
信息
- ID
- 6413
- 时间
- 1000ms
- 内存
- 64MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者