【CF453C】Little Pony and Summer Sun Celebration——楊子曰題目

【CF453C】Little Pony and Summer Sun Celebration——楊子曰題目

題目描述
Twilight Sparkle learnt that the evil Nightmare Moon would return during the upcoming Summer Sun Celebration after one thousand years of imprisonment on the moon. She tried to warn her mentor Princess Celestia, but the princess ignored her and sent her to Ponyville to check on the preparations for the celebration.
在這裏插入圖片描述
Twilight Sparkle wanted to track the path of Nightmare Moon. Unfortunately, she didn’t know the exact path. What she knew is the parity of the number of times that each place Nightmare Moon visited. Can you help Twilight Sparkle to restore any path that is consistent with this information?

Ponyville can be represented as an undirected graph (vertices are places, edges are roads between places) without self-loops and multi-edges. The path can start and end at any place (also it can be empty). Each place can be visited multiple times. The path must not visit more than 4n 4n places.

輸入格式:
The first line contains two integers n and m (2n105;0m1052 ≤ n ≤ 10^5; 0 ≤ m ≤ 10^5) — the number of places and the number of roads in Ponyville. Each of the following m lines contains two integers ui, vi (1 ≤ ui, vi ≤ n; ui ≠ vi), these integers describe a road between places uiu_i and viv_i.

The next line contains n integers: x1,x2,...,xn(0xi1)x_1, x_2, ..., x_n (0 ≤ x_i ≤ 1)— the parity of the number of times that each place must be visited. If xi = 0, then the i-th place must be visited even number of times, else it must be visited odd number of times.

輸出格式:
Output the number of visited places k in the first line (0 ≤ k ≤ 4n). Then output k integers — the numbers of places in the order of path. If xi=0x_i = 0, then the i-th place must appear in the path even number of times, else i-th place must appear in the path odd number of times. Note, that given road system has no self-loops, therefore any two neighbouring places in the path must be distinct.

If there is no required path, output -1. If there multiple possible paths, you can output any of them.

輸入樣例#1:

3 2
1 2
2 3
1 1 1

輸出樣例#1:

3
1 2 3

輸入樣例#2:

5 7
1 2
1 3
1 4
1 5
3 4
3 5
4 5
0 1 0 1 0

輸出樣例#2:

10
2 1 3 4 5 4 5 4 3 1 

輸入樣例#3:

2 0
0 0

輸出樣例#3:

0

這道題(還有這道題的那場比賽)爲什麼有一個如此奇怪背景(小馬寶莉???)


這道題就是給你一張圖,給出每個點經過的次數的奇偶性(0表示偶數,1表示奇數),讓你找出一條長度小於4n(n是點的個數)的滿足要求的路徑


絕對是一道思維好題

我們先來這樣想:最一開始的時候所有點經過的次數都是0,也就是所有點都經過偶數次,我們都用0表示,然後我們每經過一個節點,都把這個點上的值取反,這個值就表示了這個點經過次數的奇偶性

現在我們最開始的狀態全是0,然後我們還有目標狀態,這樣很難思考,我們稍稍轉化一下,我們能不能從目標狀態開始,然後想辦法把每個節點的值都想辦法給弄成0捏?當然可以,根據取反的性質這種想法是完全可行滴

接下來我們就來思考如何把這張圖上的每個節點的值都弄成0

我們從隨便一個點開始DFS下去,走過的節點我們就不會走了(除了回溯到它來的那個節點),這樣一來我們就形成了一顆DFS樹,我們來考慮現在所在的節點,我們已經把它DFS樹裏的子節點都走過了,現在是回溯到這個節點,此時我們保證了它子樹裏的節點全是0,接下來我們要看這個節點是0,還是1,如果是0,美滋滋,完美維護,我們直接回溯

BUT,如果是1的話我們得想辦法把它多經過一次,這樣來做一個粗暴的操作:先去它的爸爸,再回到它,然後你就發現這個節點已經成功地被我們弄成了0,而且沒有改變它的子樹,然後我們再回溯去處理它的爸爸就好了

有一個細節還需要注意:就是如果我們回溯到了根節點但是它的值還是1腫麼辦捏?,我們就少走一次,也就是就是說最後一個回溯到它的兒子,我們就不要回溯了,這樣我們就完美地保證了根節點也是0

但是題目中還有一個條件要求路徑的長度小於4n這一點我們可以保證嗎?——完全可以

對於每一個節點它可能會過去一次回來一次,這樣就有2n的代價了,我們再來考慮爲了維護當前節點是0而多走的次數,總體來看每次我們的維護操作都是2的代價,每個節點最多維護一次,這樣一來總長度是一定不會超過4n的

於是你有沒有發現,除了圖不連通,而且每個連通塊裏都有點是1的這種情況是無解的外,其他情況都是必定有解的,美滋滋~~


打代碼時注意:

  • 我們真正在代碼中判斷根節點的最後一條邊要不要回溯應該這樣來做:我們把根節點的爸爸設成一個空節點,然後DFS的過程中如果根節點需要維護,我們還是讓它維護,然後最外面需要輸出的時候看一下答案序列裏倒數第二個是不是空節點,如果時就說明最後回溯的那條邊我們需要扔掉,那我們最後經過的三個點不要輸出(分別對應維護根節點的一來一回,以及最後回溯上來的那條邊)
  • 我們在選擇最開始DFS的的根節點的時候可以選擇一個值爲1的點,這樣的話一遍DFS完以後可以判斷有沒有值爲1點和它不在同一個連通塊(無解),而且保證了有多個連通塊而且有解時(只有一個連通塊裏有值爲1的節點),我們DFS的一定是需要走的那個連通塊

c++代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;

struct Edge{
    int next,to;
}edge[maxn*2];

vector<int> ans;

int n,m,nedge=0;
int head[maxn],x[maxn],vis[maxn];

void addedge(int a,int b){
    edge[nedge].to=b;
    edge[nedge].next=head[a];
    head[a]=nedge++;
}

void dfs(int v,int fa){
    vis[v]=1;
    x[v]^=1;
    ans.push_back(v);
    for (int i=head[v];i!=-1;i=edge[i].next){
        int u=edge[i].to;
        if (vis[u]) continue;
        dfs(u,v);
        ans.push_back(v);
        x[v]^=1;
    }
    if (x[v]){
        ans.push_back(fa);
        x[fa]^=1; 
        ans.push_back(v);
        x[v]^=1;
    }
}

int main(){
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        addedge(a,b);
        addedge(b,a);
    }
    for (int i=1;i<=n;i++){
        scanf("%d",&x[i]);
    }
    int r=-1;
    for (int i=1;i<=n;i++){
        if (x[i]){
            r=i;
            break;
        }
    }
    if (r==-1){
        printf("0");
        return 0;
    }
    dfs(r,0);
    for (int i=1;i<=n;i++){
        if (x[i] && !vis[i]){
            printf("-1");
            return 0;
        }
    }
    if (ans[ans.size()-2]==0){
        printf("%d\n",ans.size()-3);
        for (int i=0;i<ans.size()-3;i++){
            printf("%d ",ans[i]);
        }
    }
    else{
        printf("%d\n",ans.size());
        for (int i=0;i<ans.size();i++){
            printf("%d ",ans[i]);
        }
    }
    return 0;
} 

參考:
https://blog.csdn.net/seven_jun/article/details/51911216

https://blog.csdn.net/largecub233/article/details/58073303

感謝可耐滴小慕容的講解

於HG機房

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