洛谷 P2731 騎馬修柵欄 Riding the Fences之尤拉路徑板子

Nightmares_oi發表於2024-08-10

洛谷P2731題解


傳送錨點


摸魚環節

[USACO3.3] 騎馬修柵欄 Riding the Fences

題目背景

Farmer John 每年有很多柵欄要修理。他總是騎著馬穿過每一個柵欄並修復它破損的地方。

題目描述

John 是一個與其他農民一樣懶的人。他討厭騎馬,因此從來不兩次經過一個柵欄。

John 的農場上一共有 \(m\) 個柵欄,每一個柵欄連線兩個頂點,頂點用 \(1\)\(500\) 標號(雖然有的農場並沒有那麼多個頂點)。一個頂點上至少連線 \(1\) 個柵欄,沒有上限。兩頂點間可能有多個柵欄。所有柵欄都是連通的(也就是你可以從任意一個柵欄到達另外的所有柵欄)。John 能從任何一個頂點(即兩個柵欄的交點)開始騎馬,在任意一個頂點結束。

你需要求出輸出騎馬的路徑(用路上依次經過的頂點號碼錶示),使每個柵欄都恰好被經過一次。如果存在多組可行的解,按照如下方式進行輸出:如果把輸出的路徑看成是一個 \(500\) 進位制的數,那麼當存在多組解的情況下,輸出 \(500\) 進製表示法中最小的一個 (也就是輸出第一位較小的,如果還有多組解,輸出第二位較小的,以此類推)。

輸入資料保證至少有一個解。

輸入格式

第一行一個整數 \(m\),表示柵欄的數目。

從第二行到第 \((m+1)\) 行,每行兩個整數 \(u,v\),表示有一條柵欄連線 \(u,v\) 兩個點。

輸出格式

\((m+1)\) 行,每行一個整數,依次表示路徑經過的頂點號。注意資料可能有多組解,但是隻有上面題目要求的那一組解是認為正確的。

資料保證至少有一組可行解。

樣例 #1

樣例輸入 #1

9
1 2
2 3
3 4
4 2
4 5
2 5
5 6
5 7
4 6

樣例輸出 #1

1
2
3
4
2
5
4
6
5
7

提示

對於 \(100\%\) 的資料,\(1 \leq m \leq 1024,1 \leq u,v \leq 500\)

題目翻譯來自NOCOW。

USACO Training Section 3.3


這一把熟人局,老將Farmer john申請出戰還是日常幫助Farmer john處理休閒問題。今日份的john也是閒的蛋疼騎上了馬。不出意外的話就要出題,他居然還想修柵欄,直接幹出一道尤拉路徑。


正片開始

  1. 我們選擇用vector存個圖,並將每個點所連線的點按照大小排序,以此處理輸出順序。

code:

for(int i=1;i<=m;i++)
{
    int u,v;cin>>u>>v;
    g[u].push_back(v);g[v].push_back(u);
    b[u][v]++,b[v][u]++;n=max(n,max(u,v));
}
for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());
  1. 開始搞點,不斷遍歷每個點的臨界點,在\(a\)\(b\)有邊的情況下進行遞迴處理,並將邊刪除以免重複計算。

code:

void findx(int x)
{
    for(int i=0;i<g[x].size();i++)
    {
        if(b[x][g[x][i]]>0)
        {
            b[x][g[x][i]]--,b[g[x][i]][x]--;
            findx(g[x][i]);
        }
    }
    ans[++l]=x;
}
  1. 特判不是尤拉回路的情況,即存在\(g[i].size()\)為奇數。

code:

for(int i=1;i<=n;i++)
{
    if(g[i].size()%2)
    {
        findx(i);f=1;
        break;
    }
}
if(f==0)
{
    for(int i=1;i<=n;i++)
    {
        if(g[i].size())
        {
            findx(i);
            break;
        }
    }
}
for(int i=l;i>=1;i--) cout<<ans[i]<<endl;

完整程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+10;
int m,b[N][N],ans[N],l=0,n=0,f=0;
vector<int>g[N];
void findx(int x)
{
    for(int i=0;i<g[x].size();i++)
    {
        if(b[x][g[x][i]]>0)
        {
            b[x][g[x][i]]--,b[g[x][i]][x]--;
            findx(g[x][i]);
        }
    }
    ans[++l]=x;
}
int main()
{
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v;cin>>u>>v;
        g[u].push_back(v);g[v].push_back(u);
        b[u][v]++,b[v][u]++;n=max(n,max(u,v));
    }
    for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());
    for(int i=1;i<=n;i++)
    {
        if(g[i].size()%2)
        {
            findx(i);f=1;
            break;
        }
    }
    if(f==0)
    {
        for(int i=1;i<=n;i++)
        {
            if(g[i].size())
            {
                findx(i);
                break;
            }
        }
    }
    for(int i=l;i>=1;i--) cout<<ans[i]<<endl;
    return 0;
}

完結收工!!!!!

個人主頁

看完點贊,養成習慣

\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)