程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj2337 歐拉路徑,poj2337歐拉路徑

poj2337 歐拉路徑,poj2337歐拉路徑

編輯:C++入門知識

poj2337 歐拉路徑,poj2337歐拉路徑


poj2337

這道題昨天晚上開始做,今天才A。但是問題想透了, 發現其實沒那麼難

題目大意: 
給你一些單詞,如果一個單詞的末尾字符與另一個單詞首字符相同,則兩個的單詞可以連接。問是否可以把所有單詞連接起來,並且每個單詞只能用一次。 
分析: 
可以把每個單詞看成是一條邊,單詞的首尾字符看做是兩個相連的點。我們可以把它看成有向圖的歐拉路徑問題(歐拉路徑,歐拉回路不太明白的自己百度吧)。 
一個有向圖含有歐拉通路,首先圖是連通的,並且當且僅當該圖所有頂點的入度 =出度, 或者起始頂點入度 = 出度 - 1 ,結束點 出度=入度-1, 其余點入度= 出度。明白了這些,我們的思路也就清晰啦! 
重點來啦:首先判斷圖是否連通的,在判斷圖是否存在歐拉路徑,如果都符合那就找路徑。

 

#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<algorithm>
using namespace std;

int out[30], in[30], step[1005], pre[30];
int n, k, t, st;
char w[25];

struct Edge//結構體:邊, 存儲了邊的起點(首字符)和終點(尾字符),狀態(是否走過)
{
    int s, e, v;
    char c[25];
}edge[1005];

bool cmp(Edge x, Edge y)
{
    return strcmp(x.c, y.c) < 0 ? true : false;
}
int find(int x)//查找其父節點
{
    if(pre[x] != x)
        pre[x] = find(pre[x]);
    return pre[x];
}
int panduan()//判斷是否圖是連通的
{
    int fx = find(edge[1].s);
    for(int i = 1; i <= 26; i++)
    {
        if(out[i] > 0 || in[i] > 0)
        {
            if(find(i) != fx)
                return 0;
        }
    }
    return 1;
}
void path(int en)//查找路徑
{
    for(int i = 1; i <= n; i++)
    {
        if(edge[i].v == 0 && edge[i].s == en)
        {
            edge[i].v = 1;
            path(edge[i].e);
            step[++k] = i;
        }
    }
}
int main()
{
    cin >> t;
    while(t--)
    {
        memset(out, 0, sizeof(out));
        memset(in, 0, sizeof(in));
        memset(step, 0, sizeof(step));
        for(int i = 1; i <= 30; i++)
            pre[i] = i;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            cin >> w;
            int len = strlen(w);
            int s = w[0] - 'a' + 1;
            int e = w[len - 1] - 'a' + 1;
            edge[i].s = s;
            edge[i].e = e;
            strcpy(edge[i].c, w);
            edge[i].v = 0;

            out[s]++;
            in[e]++;
            /*如果存在歐拉路徑,那麼所有的點一定都連通.所有的點都在一個集合裡,可以用並查集知識
            將所有連接的點並到一起。*/
            int fx = find(s);
            int fy = find(e);
            if(fx != fy)
                pre[fx] = fy;
        }
        sort(edge + 1, edge + 1 + n, cmp);//題目要求字典序最小輸出,就先按從小到大的順序把邊(單詞)排好
        /*st代表的是路徑起點,在這裡進行st = edge[1].s賦值,是應為存在兩種情況:1.存在一定點出度>入度,
        這個點是起點。2.所有點出度= 入度, 那麼從任意一點出發都可以, 為了保證字典序最小, 就從第一個單詞開始*/
        st = edge[1].s;
        int i, c1 = 0, c2 = 0;
        for(i = 1; i <= 26; i++)//判斷是否有歐拉回路
        {
            if(out[i] == in[i])continue;
            else if(in[i] == out[i] - 1) {c1++; st = i;}//起點
            else if(in[i] == out[i] + 1) c2++;
            else break;
        }
        //如果符合了連通圖,並且存在歐拉通路, 就開始找路徑
        if(i == 27 && ((c1 == c2 && c1 == 1) || (c1 == c2 && c1 == 0)) && panduan() == 1)
        {
            k = 0;
            path(st);
            for(int i = n; i > 1; i--)//輸出這注意點,因為是遞歸求的路徑, 最先得到的是最後的邊
                printf("%s.", edge[step[i]].c);
            printf("%s\n", edge[step[1]].c);
        }
        else
            printf("***\n");
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved