pku 2337 Catenyms(寻找欧拉通路)

以字母为节点,字符串为边,寻找欧拉回路。

一开始不会,用的深搜回溯找的路径。后来问了lvyun,才知道有个很好用的套圈法,每条边只要走一次O(e)的效率。

关于套圈法,可以参看http://blog.csdn.net/logic_nut/archive/2009/08/23/4474307.aspx

深搜回溯

#include <iostream> using namespace std; int degree_in[26],degree_out[26],edge_num,edge_order[1005]; bool used[1005]; struct Edge { int start,end; char word[25]; }edges[1005]; int CMP(const void* a,const void* b) { Edge *c=(Edge*)a,*d=(Edge*)b; if(c->start!=d->start) return c->start-d->start; else return strcmp(c->word,d->word); } inline int ABS(int a) { if(a>0) return a; else return -a; } int check()//返回起点 { int cnt1=0,cnt2=0,source; for(int i=0;i<26;i++) { if(ABS(degree_in[i]-degree_out[i])==2) return -1; else if(degree_in[i]-degree_out[i]==1) { cnt1++;//基度顶点计数 } else if(degree_in[i]-degree_out[i]==-1) { cnt2++;//基度顶点计数 source=i; } } if(cnt1>1||cnt2>1) return -1; else if(cnt1==0) { for(int i=0;i<26;i++) if(degree_out[i]) return i; } else return source; } bool solve_dfs(int source,int cnt) { if(cnt==edge_num) return true; for(int i=0;i<edge_num;i++) { if(edges[i].start<source||used[i]) continue; else if(edges[i].start>source) return false; used[i]=true; edge_order[cnt]=i; if(solve_dfs(edges[i].end,cnt+1)) return true; used[i]=false; } return false; } int main() { int t; scanf("%d",&t); while(t--) { memset(degree_out,0,sizeof(degree_out)); memset(degree_in,0,sizeof(degree_in)); scanf("%d",&edge_num); for(int i=0;i<edge_num;i++) { scanf("%s",edges[i].word); edges[i].start=edges[i].word[0]-'a'; edges[i].end=edges[i].word[strlen(edges[i].word)-1]-'a'; degree_out[edges[i].start]++; degree_in[edges[i].end]++; } int source=check(); if(source==-1) { printf("***/n"); continue; } qsort(edges,edge_num,sizeof(edges[0]),CMP); memset(used,0,sizeof(used)); if(!solve_dfs(source,0)) { printf("***/n"); continue; } printf("%s",edges[edge_order[0]].word); for(int i=1;i<edge_num;i++) { printf(".%s",edges[edge_order[i]].word); } printf("/n"); } }

 

套圈法(three_up队lvyun的代码)

#include <iostream> using namespace std; struct adjLink { int v, nxt; char word[30]; }adj[2000]; int adjN; void insert(int beg, int end, char word[30])//类似于hash,第一个节点数据域不存值只有指针部分有效。链表中单词按字典序排列。 { int i; for (i = beg; adj[i].nxt != -1; i = adj[i].nxt) if (strcmp(adj[adj[i].nxt].word, word) >= 0) break; adj[adjN].v = end; strcpy(adj[adjN].word, word); adj[adjN].nxt = adj[i].nxt; adj[i].nxt = adjN++; } int vis[30], count; void dfs(int cur)//检查连通性 { vis[cur] = 1; count++; for (int i = adj[cur].nxt; i != -1; i = adj[i].nxt) if (!vis[adj[i].v]) dfs(adj[i].v); } int path[2000], npath; void euler(int cur, int edgeN) //cur当前到达的节点 edgeN上一被选择的边,即上一个节点通过edgeN到达的cur { int i; while(adj[cur].nxt != -1) { i=adj[cur].nxt; adj[cur].nxt=adj[i].nxt; euler(adj[i].v,i); } path[npath++] = edgeN; //后序记录 输出的时候为了保证字典序,需逆向输出 } void go() { int n, i; scanf("%d", &n); for (i = 0; i < 26; i++) adj[i].nxt = -1; adjN = i; int flag[30], tot = 0, cnt[30]; memset(flag, 0, sizeof(flag)); memset(cnt, 0, sizeof(cnt)); for (i = 0; i < n; i++) { char word[30]; scanf("%s", &word); int a = word[0] - 'a', b = word[strlen(word) - 1] - 'a'; int len = strlen(word); word[len] = '.'; word[len + 1] = 0; insert(a, b, word); cnt[b]--; cnt[a]++; if (!flag[a]) flag[a] = 1, tot++; if (!flag[b]) flag[b] = 1, tot++; } for (i = 0; i < 26; i++) { memset(vis, 0, sizeof(vis)); count = 0; dfs(i); if (count == tot) break; } if (i == 26) { printf("***/n"); return ; } int flagIn = 0, flagOut = 0, flagNo = 0, site; for (i = 0; i < 26; i++) if (cnt[i] == -1) flagIn++; else if (cnt[i] == 1) flagOut++, site = i; else if (cnt[i]) flagNo = 1; if (flagNo || flagIn > 1 || flagOut > 1 || flagIn != flagOut)//根据欧拉通路的充要条件 将不符合的先排除掉 { printf("***/n"); return ; } npath = 0; if (flagOut == 0) { for (i = 0; i < 26; i++) if (adj[i].nxt != -1) { site = i; break; } } euler(site, -1); //因为直接从site出发,所以第二个参数用-1代替,输出的时候要忽略掉。 for (i = npath - 2; i > 0; i--) printf("%s", adj[path[i]].word); int len = strlen(adj[path[0]].word); adj[path[0]].word[len - 1] = 0; printf("%s/n", adj[path[0]].word); } int main() { int T; scanf("%d", &T); while (T--) go(); return 0; }

 

你可能感兴趣的:(c,struct,insert,UP,Path,Go)