POJ 2438 Children's Dining (求哈密頓迴路模板)

題目大意:

n個孩子要求圍成一圈,有m對敵對關係,有敵對關係的孩子不能相鄰,輸出一種方案。


解題思路:

有神犇說是特殊圖所以可以用哈密頓迴路做,不懂,姑且當作寫個模板。


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<bitset>
#define LL long long
#define db double
#define EPS 1e-15
#define inf 1e10
#define pa pair<int,int>

using namespace std;

const int maxn=420;
int n,m;
bool mp[maxn][maxn];
int S,T,cnt,ans[maxn];
bool vis[maxn];

void reverse(int l,int r){
    while (l<r){
        swap(ans[l],ans[r]);
        l++,r--;
    }
}
void expend(){
    for (;;){
        bool flag=0;
        for (int i=1;i<=n;i++){
            if (!vis[i] && mp[T][i]){
                ans[cnt++]=i;
                T=i;
                vis[i]=1;
                flag=1;
                break;
            }
        }
        if (!flag) break;
    }
}
void hamiltun(){
    memset(vis,0,sizeof(vis));

    S=1;
    for (T=2;T<=n;T++) if (mp[S][T]) break; 
    //任意找兩個相鄰的節點S和T
    
    cnt=2;
    ans[0]=S, ans[1]=T;
    vis[S]=1, vis[T]=1;
    while (1) {
        expend();  
        //在它們的基礎上擴展出一條儘量長的沒有重複節點的路徑
        reverse(0,cnt-1);
        swap(S,T);
        expend();
        //在它們的基礎上擴展出一條儘量長的沒有重複節點的路徑

        int mid=0;
        if (!mp[S][T]){
        //若S與T不相鄰,可以構造出一個迴路使新的S和T相鄰

            for (int i=1;i<cnt-2;i++){
            // 設路徑S到T上有k+2個節點,依次爲S,v1,v2…… vk和T.
            // 可以證明存在節點vi,滿足vi與T相鄰,且vi+1與S相鄰
                if (mp[ans[i]][T] && mp[ans[i+1]][S]){
                    mid=i+1;
                    break;
                }
            }
            reverse(mid,cnt-1);
            //把原路徑變成S→vi→T→vi+1→S,即形成了一個迴路 

            T=ans[cnt-1];
        }
        if (cnt==n) break;
        //現在我們有了一個沒有重複節點的迴路.如果它的長度爲N,則漢密爾頓迴路就找到了  
        //否則,由於整個圖是連通的,所以在該回路上,一定存在一點與迴路以外的點相鄰  
        //那麼從該點處把迴路斷開,就變回了一條路徑,再按照步驟1的方法儘量擴展路徑
        for (int i=1;i<=n;i++){
            if (!vis[i]){
                int j;
                for (j=1;j<cnt-1;j++)
                    if (mp[ans[j]][i]) break;
                if (mp[ans[j]][i]){
                    T=i; mid=j;
                    break;
                }
            }
        }
        S=ans[mid-1];
        reverse(0,mid-1);
        reverse(mid,cnt-1);
        ans[cnt++]=T;
        vis[T]=1;
    }
}
int main(){
    int u,v;
    while (scanf("%d%d",&n,&m)!=EOF){
        if (n==0 && m==0) break;
        n<<=1;
        memset(mp,1,sizeof(mp));
        for (int i=1;i<=n;i++) mp[i][i]=0;
        for (int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            mp[u][v]=0;
            mp[v][u]=0;
        }
        hamiltun();
        printf("%d",ans[0]);
        for (int i=1;i<cnt;i++)
            printf(" %d",ans[i]);
        puts("");
    }   
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章