首先想到的是并查集,然后WA。。。原因在这,我第一次敲的是Find(1) == Find(12)来作为可以成功的条件,实际上这样是不行的,比方说 bell 和 mail实际上是不满足条件的,可以理解为有向边,合并的时候要注意是首尾相接,可以改为Find(1) == 12 或者 Find(12) == 1,具体取决于并查集父子节点的合并关系,其次可以使用弗洛伊德算法或者DFS都可以。
并查集:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 26 + 5; int pre[N]; int Find(int x){ return pre[x] == x? x : (pre[x] = Find(pre[x])); } void Merge(int x, int y){ x = Find(x), y = Find(y); if(x != y) pre[x] = y; //这里要注意, 如果是pre[y] = x, 则要Find(12) == 1 } char ch[N*10000]; int main(){ while(scanf("%s", ch) == 1){ for(int i = 0; i < 26; i++) pre[i] = i; while(ch[0] != '0'){ int x = ch[0] - 'a'; int y = ch[strlen(ch) - 1] - 'a'; Merge(x, y); scanf("%s", ch); } printf("%s ",Find(1) == 12?"Yes.":"No."); } return 0; }
弗洛伊德:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 26 + 5; const int INF = 0x3f3f3f3f; int mat[N][N]; void Flory(){ for(int k = 0; k < 26; k++) for(int i = 0; i < 26; i++) for(int j = 0; j < 26; j++) mat[i][j] = min(mat[i][j], mat[i][k] + mat[k][j]); } void Init(){ for(int i = 0; i < 26; i++) for(int j = 0; j < 26; j++) mat[i][j] = (i!=j)?INF:0; } char ch[10010]; int main(){ while(scanf("%s", ch) == 1){ Init(); while(ch[0] != '0'){ int x = ch[0] - 'a'; int y = ch[strlen(ch)-1] - 'a'; mat[x][y] = 1; //有向边 scanf("%s", ch); } Flory(); printf("%s. ",mat[1][12] < INF?"Yes":"No"); } return 0; }
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 26 + 5; bool dp[N][N],can; void DFS(int x){ if(can) return ; if(can = (x == 12)) return ; for(int i=0; i < 26; i++) if(dp[x][i]){ dp[x][i] = false; DFS(i); dp[x][i] = true; } } void Init(){ for(int i = 0; i < 26; i++) for(int j = 0; j < 26; j++) dp[i][j] = false; can = false; } char ch[10010]; int main(){ while(scanf("%s", ch) == 1){ Init(); while(ch[0] != '0'){ int x = ch[0] - 'a'; int y = ch[strlen(ch)-1] - 'a'; dp[x][y] = true; scanf("%s", ch); } DFS( 1 ); printf("%s. ", can?"Yes":"No"); } }