Description
Input
Output
Sample Input
a b f g a b b f v w x y z v y x v z v w v
Sample Output
abfg abgf agbf gabf wxzvy wzxvy xwzvy xzwvy zwxvy zxwvy
开始用深度搜索的方式,结果没有想全面,这样做的话就会出现关系没法传递的现象,结果算法全部都是错误的,做了那么长时间,竟然一点都不对,哎。。。
#include<iostream> #include <string> #include <cstdio> #include <cstring> using namespace std; bool map[150][150]; char ch[50],limit[150],temp[250]; string s; int len2,len1; void makemap() { memset(map,0,sizeof(map)); int i,j; for(i=0;i<len1;i++) for( j=0;j<len1;j++) if(ch[i]!=ch[j]) map[ch[i]][ch[j]]=1; for(i=0;i<len2;i+=2) map[ limit[i+1] ][ limit[i] ]=0; for(i='a';i<='z';i++) { for(int j='a';j<='z';j++) cout<<map[i][j]<<' '; cout<<endl; } } void dfs(int x,int k,string s) { s=s+char(x); //记录路径 if(k==len1-1) //记录路径的长度 { cout<<s<<endl; return ; } for(int y='a';y<='z';y++) if(map[x][y]) { string str=""; for(int i='a';i<='z';i++) if(map[i][x]==1) { map[i][x]=0; str=str+char(i); } map[x][y]=0; dfs(y,k+1,s); for(int j=0;j<str.size();j++)//恢复原形状 map[str[j]][x]=1; map[x][y]=1; } } int main () { int len; while(cin.getline(temp,30,'\n')) { int i=0; len=strlen(temp); int j=0; while(j<len) { if(temp[j]!=' ') ch[i++]=temp[j]; j++; } ch[i]='\0'; printf("%s\n",ch); i=j=0; cin.getline(temp,30,'\n'); len=strlen(temp); while(j<len) { if(temp[j]!=' ') limit[i++]=temp[j]; j++; } limit[i]='\0'; printf("%s\n",limit); len2=strlen(limit); len1=strlen(ch); cout<<len1<<"&&&&&&&&&&&&&&&&&&&&&&&&&&"<<endl; makemap(); for(i=0;i<len1;i++) dfs(ch[i],0,""); } return 0; }
拓扑排序,通过对节点和入度(产生限制)和出度(解除限制)来实现是否能访问该节点的作用
#include<iostream> #include<cstring> #include<string> using namespace std; int len; int pre[300]; // 存字母入度 // 把小写字母的ascii码都包括在内 //入度和出度其实就是和树一样,不过在本算法中入度指的是收到来自其他字母的限制 bool has[300]; //节点标志 // 把小写字母的ascii码都包括在内,如果节点是1的话就能访问 string var,v; //var 变量串 v 约束串 void dfs(int dep,string res) { if(dep==len) { //第n+1个字母不用找(即找完n个字母时结束) cout<<res<<endl; return ; } for(int i='a';i<='z';i++)//按字典顺序遍历查找入度为0的节点,释放该节点 if( has[i] && pre[i]==0 ) //该节点存在且该节点没有被限制 { has[i]=false;//删除点,标记该点不能再访问了 int k; for(k=0;k<v.length();k+=4)//该节点限制的所有的字母接触当前字母的限制,即减一 if(v[k]==i) -- pre[ v[k+2] ] ; //解除本限制 dfs(dep+1,res+char(i)); for(k=0;k<v.length();k+=4)//恢复被删边 if(v[k]==i) ++ pre[v[k+2]] ; has[i]=true; //恢复节点 } } int main() { while(getline(cin,var)&&getline(cin,v)) { memset(pre,0,sizeof(pre)); //初始化节点标志,初始时都不是节点 memset(has,0,sizeof(has)); //初始化节点入度,初始为都没有限制 int i; for(i=0;i<var.length();i+=2)//初始节点标志 has[ var[i] ]=true; len=var.length()/2 +1; //n为节点数 for(i=0;i<v.length();i+=4)//统计节点入度 v.lenth()=v.size() ++ pre[ v[i+2] ] ; dfs(0,""); //第一个参数为已经有多少个已经访问过的数 cout<<endl; } return 0; }
最笨的办法,将所有的全排列全部列出,然后筛选,不过由于后台的数据不是很多,所以不会超时,就是这道题的输入比较屌丝,其实由于输入是正确的。将输入的
#include <iostream> #include <string> #include <algorithm> using namespace std; int len1,len2; string t; char ch[200], limit[200]; int cmp(const void* p, const void* q) { return *(char*)p - *(char*)q; }//比较函数,从小到大排序 bool isvalid() {// char p, q; int i, j; //i记录已经排好序的当前位置指针,j记录条件的当前位置 // cout<<"进入判断:"<<endl; // cout<<"*************"<<ch<<endl<<limit<<endl<<"************"<<endl; for (j=0; j < len2; j++) { p = limit[j*2]; q = limit[j*2+1]; //两个为一对 <span style="color:#ff0000;"> for (i=0; i <len1; i++) //如果与条件冲突返回false { if (ch[i] == p) //如果先出现了前面一个,也就是顺序是对的,忽略掉本次循环 break; if (ch[i] == q) //如果是先出现了后面的那个,也就是顺序是错误的,就返回错误 return false; } </span> } return true; } int main() { char temp [300]; while(cin.getline(temp,50,'\n')) { int i=0; int len=strlen(temp); int j=0; while(j<len) { if(temp[j]!=' ') ch[i++]=temp[j]; j++; } ch[i]='\0'; // printf("%s\n",ch); i=j=0; cin.getline(temp,105,'\n'); len=strlen(temp); while(j<len) { if(temp[j]!=' ') limit[i++]=temp[j]; j++; } // printf("%s\n",limit); limit[i]='\0'; len1 = strlen(ch); len2=strlen(limit); qsort(ch, len1, sizeof(char), cmp);//按字典序排序 if (isvalid()) printf("%s\n", ch); while<span style="color:#ff0000;">(next_permutation(ch, ch+len1))//</span>用STL中的求排列组合函数求所有序列,新的排列顺序为当前排序的下一个排列方式 if (isvalid())//判断当前序列是否符合给出的限制条件 printf("%s\n", ch);//符合输出 printf("\n"); } return 0; }