首先图必定是连通的!!(这个就不用解释了)
图的连通性可以通过并查集或者DFS判断
当且仅当该图所有顶点度数都为偶数。
因为这时通过一条边进入一个顶点,必然能从另一条边离开该顶点。
如果当且仅有两个点的度数是奇数的话,则存在欧拉路径,并且起点和终点分别为两个度数为奇数的顶点中的一个。(这时在这两个点之间连一条无向边就存在欧拉回路了)
当且仅当所有顶点的入度等于出度。
保证进入顶点之后能够离开该顶点,否则进入某个点之后就不能离开这个点。
如果其中仅有一个点出度比入度大1,并且仅有一个点出度比入度小1,则存在欧拉路径,并且前者为起点,后者为终点。(从终点向起点连接一条有向边就存在欧拉回路了)
可能要花一点时间想一想,但是明白了就觉得很简单了,代码比较简短,根据代码画图跑一遍。(首先要确定存在欧拉回路)可以从起点开始不断寻找路径,可能会走到死胡同。第一次到达死胡同的时候必定是走到了终点(如果原图存在欧拉回路的话就回到了起点,是欧拉路径的话就到达了终点),可以思考一下为什么,这时剩余的边必定能形成欧拉回路,因为此时所有剩余点的度数为偶数(如果是有向图,剩余点的入度和出度相同)。此时回溯到一个可以扩展的点(把回溯过程中的点加入到栈中,记录路径)继续搜索,寻找子欧拉回路(寻找到之后的终点和起点必定相同),把子欧拉回路加入到已找到的欧拉回路中依然是一个欧拉回路。
(欧拉图可以看成是若干个子欧拉图的组成)
下面的代码可以用于寻找欧拉回路和欧拉路径:
时间复杂度为O(E)
iter[MAXE];
memset(iter,0,sizeof(iter)); //记录各顶点当前找到的边,用于优化时间
void dfs(int now){
for(int &i=iter[now];i<n;i++){
if(G[now][i]){
G[now][i] = G[i][now] = 0;//如果是有向图就改成 G[now][i] = 0;
dfs(i);
}
}
stk.push(now); //用来存储经过的顶点
}
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 255;
int degree[maxn],have[maxn],bin[maxn],iter[maxn];
int cnt = 0,st = 0;
int G[maxn][maxn];
int n;
stack<int> ans;
int findx(int x){
if(x!=bin[x]) bin[x] = findx(bin[x]);
return bin[x];
}
void unity(int a,int b){
int fa = findx(a);
int fb = findx(b);
if(fa!=fb) bin[fa] = fb;
}
void add_edge(int x,int y){
have[x] = have[y] = 1;
degree[x]+=1;
degree[y]+=1;
G[x][y] = G[y][x] = 1;
}
void input(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
char pat[3];
scanf("%s",pat);
int pa=pat[0],pb=pat[1];
add_edge(pa,pb);
unity(pa,pb);
}
}
bool check(){
int res;
for(int i='A';i<='z';i++){
if(have[i]){
res = bin[i];
break;
}
}
for(int i='A';i<='z';i++) if(have[i]&&(bin[i]!=res)) return false;
for(int i='A';i<='z';i++){
if(have[i]&&(degree[i]&1)){
cnt++;
st = st ? min(st,i) : i;
}
if(cnt>2) return false;
}
return true;
}
void dfs(int cur){
for(int &i=iter[cur];i<='z';i++){
if(G[cur][i]){
G[cur][i] = G[i][cur] = 0;
dfs(i);
}
}
ans.push(cur);
}
int main(){
input();
fill(iter,iter+maxn,'A');
if(!check()){
printf("No Solution\n");
return 0;
}
if(st==0){
for(int i='A';i<='z';i++){
if(have[i]){
st = i;
break;
}
}
}
dfs(st);
while(!ans.empty()){
printf("%c",ans.top());
ans.pop();
}
return 0;
}
题目保证给定的图连通,所以就不用判断连通性了
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2333;
const int maxm = 50;
int G[maxm][maxn];
stack<int> ans;
int vis[maxn];
int iter[maxm],degree[maxm],lst,cnt,home;
void add_edge(int u,int v,int k){
G[u][k] = v;
G[v][k] = u;
}
void init(){
cnt = lst = 0;
memset(vis,0,sizeof(vis));
memset(iter,0,sizeof(iter));
memset(degree,0,sizeof(degree));
memset(G,0,sizeof(G));
}
bool input(){
init();
int pa,pb,k;
while(scanf("%d %d",&pa,&pb)){
if(!(pa+pb)) return cnt!=0;
if(cnt==0) home = pa < pb ? pa : pb;
scanf("%d",&k);
add_edge(pa,pb,k);
lst = max(lst,max(pa,pb));
cnt = max(k,cnt);
degree[pa]++;
degree[pb]++;
}
}
bool check(){
for(int i=1;i<=lst;i++) if(degree[i]&1) return false;
return true;
}
void dfs(int now){
for(int &i=iter[now];i<=cnt;i++){
if(!vis[i]&&G[now][i]){
int tmp = i;
vis[i] = 1;
dfs(G[now][i]);
ans.push(tmp);
}
}
}
void print(){
while(!ans.empty()){
ans.size()==1 ? printf("%d",ans.top()) : printf("%d ",ans.top());
ans.pop();
}
printf("\n");
}
int main(){
while(input()){
if(!check()){
printf("Round trip does not exist.\n");
continue;
}
dfs(home);
print();
}
return 0;
}
#include
#include
#include
using namespace std;
const int maxn = 233;
int T,n;
int have[maxn],bin[maxn],indegree[maxn],outdegree[maxn];
void init(){
memset(have,0,sizeof(have));
memset(indegree,0,sizeof(indegree));
memset(outdegree,0,sizeof(outdegree));
for(int i=0;i<maxn;i++) bin[i] = i;
}
int findx(int x){
if(x!=bin[x]) bin[x] = findx(bin[x]);
return bin[x];
}
void unity(int x,int y){
int fx = findx(x);
int fy = findx(y);
if(fx!=fy) bin[fx] = fy;
}
void input(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
char tmp[1111];
scanf("%s",tmp);
int len = strlen(tmp);
indegree[tmp[0]]++;
outdegree[tmp[len-1]]++;
have[tmp[0]] = 1;
have[tmp[len-1]] = 1;
unity(tmp[0],tmp[len-1]);
//printf("%d %d\n",bin[tmp[0]],bin[tmp[len-1]]);
}
}
bool check(){
int target;
for(int i='a';i<='z';i++){
if(have[i]){
target = findx(i);
break;
}
}
int cnta=0,cntb=0;
for(int i='a';i<='z';i++){
int del = indegree[i]-outdegree[i];
if(del==1) cnta++;
if(del==-1) cntb++;
if(del<-1||del>1) return false;
if(have[i]&&findx(i)!=target) return false;
}
if(cnta==cntb&&(cnta==0||cnta==1)) return true;
return false;
}
int main(){
scanf("%d",&T);
while(T--){
init();
input();
if(check()) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
typedef pair<int,int> IntPair; //first表示通往的节点编号,second表示边的使用情况
const int maxn = 1e4+7;
int n,m;
vector<IntPair> G[maxn];
stack<int> ans;
int iter[maxn];
void init(){
for(int i=0;i<maxn;i++) G[i].clear();
memset(iter,0,sizeof(iter));
}
void add_edge(int u,int v){
G[u].push_back(make_pair(v,0));
G[v].push_back(make_pair(u,0));
}
void input(){
for(int i=1;i<=m;i++){
int pa,pb;
scanf("%d %d",&pa,&pb);
add_edge(pa,pb);
}
}
void euler(int now){
for(int &i=iter[now];i<G[now].size();i++){
if(!G[now][i].second){
G[now][i].second = 1;
euler(G[now][i].first);
}
}
ans.push(now);
}
void output(){
while(!ans.empty()){
printf("%d\n",ans.top());
ans.pop();
}
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
init();
input();
euler(1);
output();
}
return 0;
}
#include
#include
#include
using namespace std;
const int maxn = 5e5+7;
struct NODE{
int id;
NODE* next[26];
};
int bin[maxn],indegree[maxn];
int node_cnt;
NODE* build(){
NODE* node = (NODE*)malloc(sizeof(NODE));
memset(node->next,0,sizeof(node->next));
node->id = 0;
return node;
}
int get_id(NODE *root,char* s){
char* p = s;
NODE *now = root;
while(*p){
int k = *p-'a';
if(now->next[k]==NULL) now->next[k] = build();
now = now->next[k];
p++;
}
return now->id ? now->id : now->id=++node_cnt;//如果没有标记 给出序号标记并返回
}
int findx(int x){
if(x!=bin[x]) bin[x] = findx(bin[x]);
return bin[x];
}
void unity(int a,int b){
int fa = findx(a);
int fb = findx(b);
if(fa!=fb) bin[fa] = fb;
}
void input_build(NODE* root){
memset(indegree,0,sizeof(indegree));
node_cnt = 0;
for(int i=0;i<maxn;i++) bin[i] = i;
char sa[20],sb[20];
while(scanf("%s %s",sa,sb)!=EOF){
int pa = get_id(root,sa);
int pb = get_id(root,sb);
unity(pa,pb);
indegree[pa]++;
indegree[pb]++;
}
}
bool check(){
for(int i=1;i<node_cnt;i++) if(findx(i)!=findx(i+1)) return false; //判断连通性
int num = 0;
for(int i=0;i<node_cnt;i++) if(indegree[i]&1) num++; //判断节点的度是否合理
return num<=2;
}
void Trie_clear(NODE* root){
for(int i=0;i<26;i++) if(root->next[i]) Trie_clear(root->next[i]);
free(root);
}
int main(){
NODE* root = build();
input_build(root);
if(!check()) printf("Impossible\n");
else printf("Possible\n");
Trie_clear(root);
return 0;
}
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1111;
const int maxm = 30;
struct EDGE{
int to;
int next;
string str;
};
stack<string> ans;
int bin[maxm],have[maxm],head[maxm],vis[maxn];
int indegree[maxm],outdegree[maxm];
EDGE edge[maxn];
int T,n,st;
string s[maxn];
bool cmp(string &a,string &b){
return a>b;
}
int findx(int a){
if(a!=bin[a]) bin[a] = findx(bin[a]);
return bin[a];
}
void unity(int a,int b){
int fa = findx(a);
int fb = findx(b);
if(fa!=fb) bin[fa] = fb;
}
void init(){
st = -1;
for(int i=0;i<maxm;i++) bin[i] = i; //并查集前节点
memset(vis,0,sizeof(vis)); //边访问标记
memset(head,255,sizeof(head)); //链式前向星头指针
memset(have,0,sizeof(have)); //点是否使用
memset(indegree,0,sizeof(indegree)); //各点的入度
memset(outdegree,0,sizeof(outdegree)); //各点的出度
}
void input(){
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i];
int a = s[i][0]-'a';
int b = s[i][s[i].size()-1]-'a';
unity(a,b);
outdegree[a]++;
indegree[b]++;
have[a] = have[b] = 1;
}
}
bool check(){ //判断图的连通性,判断入度和出度的关系
int cnta=0,cntb=0,target;
for(int i=0;i<maxm;i++){
if(have[i]){
target = findx(i);
break;
}
}
for(int i=0;i<maxm;i++) if(have[i]&&(findx(i)!=target)) return false; //连通性
for(int i=0;i<maxm;i++){
int del = indegree[i] - outdegree[i];
if(del==1) cnta++;
else if(del==-1) st=i,cntb++; //如果有出度大于入度1的点,如果存在欧拉路径,i为起始点
else if(del<-1||del>1) return false;
}
if(cnta>1||cntb>1) return false; //有向图出入度关系
return true;
}
void add_edge(int u,int v,string& strr,int id){ //建边操作
edge[id].next = head[u];
edge[id].str = strr;
edge[id].to = v;
head[u] = id;
}
void build(){
sort(s,s+n,cmp); //对边排序,要输出字典序最小的
for(int i=0;i<n;i++){ //按顺序建边
int a = s[i][0]-'a';
int b = s[i][s[i].size()-1]-'a';
add_edge(a,b,s[i],i);
}
if(st==-1) for(int i=0;i<maxn;i++) if(have[i]){ //如果起点可以是任意的,找字典序最小的起点
st = i;
break;
}
}
void euler(int now){
for(int i=head[now];i!=-1;i=edge[i].next){
if(!vis[i]){
vis[i] = 1;
euler(edge[i].to);
ans.push(edge[i].str);
}
}
}
int main(){
ios::sync_with_stdio(false);
cin>>T;
while(T--){
init();
input();
if(!check()){
cout<<"***"<<endl;
continue;;
}
build();
euler(st);
while(!ans.empty()){
if(ans.size()==1) cout<<ans.top()<<endl;
else cout<<ans.top()<<'.';
ans.pop();
}
}
return 0;
}