icpc:problems:usaco23jan_find_and_replace_s
problems | |
---|---|
名称 | Find and Replace S |
题目编号 | USACO23JAN_S1 |
题目链接 | usaco.org/… |
来源 | USACO |
算法分类 | 基环树, 思维 |
难易程度 | 一般般 |
Find and Replace S
想法
由a 变成 b,可以记为点a存在一条指向点b的边,通过这种方式建图,我们可以得到3种形式的联通块:
- 链
- 基环树
- 环
当联通块为链时,可以通过线变链尾的边,再依次向上变化的方式来变化。变化次数为边数。
当联通块为基环树时,可以让环内的每个值变成环外的数值,来保证环上所有点均可以变化。变化次数为边数。
当联通块为环时,需要借助在图中没有的点或其他联通块入度为零的点,来进行变化,如果没有则不能变化。变化次数为边数+1。
不能变化的情况:
- 出现一对多
- 没有给环借助的点
代码实现
#include<iostream> #include<cstring> #include<string> using namespace std; const int N = 52; int tong[N], in[N]; bool vis[N], this_vis[N]; int trans(char x) { if(x >= 'a' && x <= 'z') return x - 'a'; return x - 'A' + 26; } int main() { int T; cin >> T; while(T--) { string a, b; cin >> a >> b; int len = a.length(), used = 0, cnt = 0; bool flag = false; memset(tong, -1, sizeof(tong)); memset(in, 0, sizeof(in)); memset(vis, false, sizeof(vis)); for (int i = 0; i < len; ++i) { int ai = trans(a[i]), bi = trans(b[i]); if(tong[ai] != bi && tong[ai] != -1) { flag = true; break; } if(~tong[ai])continue; tong[ai] = bi; in[bi]++; used++; } if(flag) { cout << -1 << endl; continue; } for (int i = 0; i < N; ++i) { if(tong[i] == i) tong[i] = -1; if(in[i] == 0) used--; } for (int i = 0; i < N; ++i) { if(tong[i] == -1)continue; cnt++; if(vis[i])continue; memset(this_vis, false, sizeof(this_vis)); vis[i] = this_vis[i] = true; int temp = i, curr; bool yescircle = false; while(tong[temp] != -1 && !vis[tong[temp]]) { temp = tong[temp]; vis[temp] = true; this_vis[temp] = true; } if(tong[temp] != -1 && this_vis[tong[temp]]) { curr = temp; do { if(in[curr]>=2) { yescircle = true; break; } curr = tong[curr]; } while(curr != temp); if(used < 52 && !yescircle){ cnt++; yescircle = true; } if(!yescircle) { flag = true; break; } } } if(flag) { cout << -1 << endl; } else { cout << cnt << endl; } } return 0; }
/app/www/public/data/pages/icpc/problems/usaco23jan_find_and_replace_s.txt · 最后更改: 2023/02/20 08:37 由 温婕莺