10.1 國慶節給祖國母親獻禮 NOIP 模擬題 第二題題解
2503: 相框
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 108 Solved: 52
[Submit][Status][Discuss]
Description
P大的基礎電路實驗課是一個無聊至極的課。每次實驗,T君總是提前完成,管理員卻不讓T君離開,T君只能幹坐在那兒無所事事。 先說說這個實驗課,無非就是把幾根導線和某些元器件(電阻、電容、電感等)用焊錫焊接起來。 為了打發時間,T君每次實驗做完後都在焊接一些詭異的東西,這就是他的傑作:
T君不滿足於焊接奇形怪狀的作品,強烈的破壞欲驅使他拆掉這個作品,然後將之焊接成規整的形狀。這會兒,T君正要把這個怪物改造成一個環形
T君約定了兩種操作:
1. 燒熔一個焊點:使得連接在焊點上的某些導線相分離或保持相連(可以理解為:把焊點上的導線劃分為若幹個類,相同類中的導線相連,不同類之間的導線相離)
2. 將兩根導線的自由端(即未與任何導線相連的一端)焊接起來。
例如上面的步驟中,先將A點燒熔,使得導線1與導線2、4點分離;再將D點燒熔,使得4、5與3、7相離;再燒熔E,使7與6、8相離;最後將1、7相連。
T君想用最少的操作來將原有的作品改造成為相框(要用上所有的導線)。
Input
輸入文件的第一行共有兩個整數n和m — 分別表示原有的作品的焊點和導線的數量 (0 ≤ n
原有的作品可能不是連通的。
某些焊點可能只有一根導線與之相連,在該導線的這一端與其他導線相連之前,這些焊點不允許被燒熔。
某些焊點甚至沒有任何導線與之相連,由於T君只關心導線,因此這些焊點可以不被考慮。
Output
輸出文件只包含一個整數——表示T君需要將原有的作品改造成相框的最少步數。
Sample Input
6 81 2
1 3
3 4
1 4
4 6
5 6
4 5
1 5
Sample Output
HINT
30%的數據中n≤10;
100%的數據中n≤1000。
這道題當時一看不可做,除了樣例和n=0以外直接輸出的n才20分,然而,原子核輸出了m騙到了50分%%%orz。 事實證明這道題得分除了騙來的分為兩種,一種是基本想通了所有細節,結果對於自環處理不當或其他細節險些AC的和如我一般接近爆零的。差距啊~~ 寫這篇題解之前我也不會的預備知識:
歐拉通路:從圖中一個點出發不重復地遍歷所有邊的路徑(可以停在另一個點)
歐拉回路:從圖中一個點出發不重復地遍歷所有邊的回路(必須回到出發點)
歐拉圖:存在歐拉回路的圖。判斷無向圖為歐拉圖的充要條件是所有點的度數均為偶數。
半歐拉圖:存在歐拉通路的圖。判斷無向圖為歐拉圖的充要條件是所有點的度數均為偶數或只有兩個點的度數為奇數
一個圖中如果存在度數為奇數的點,那麽這樣的點一定有偶數個。
讓我們先從最簡單的說起——它是一整個連通圖。
如果他自己已經是一個環,輸出0即可。
如果他是一個歐拉圖(我們刨去為環的情況),那麽就是所有入度大於2的點的個數,我們只要把它們都燒熔掉為若幹個入讀為2的點就好了。
對於其他情況,我們可以想到,對於入度大於2的點,我們依然要去燒熔掉,而對於入度為單數的點,當我們將入度大於2的點全部融完之後會出現 單數入度點數/2條 鏈我們還要把它們接到一起,所以答案就是 入度大於2的點數+入度為單數的點數/2;
下面說更復雜的——它是若幹個連通圖。
此時如果他自己是一個環,那麽我們就需要把它融開,使它成為一條鏈和其他鏈去拼接在一起,ans++,sum(鏈數)++。
如果他是一個歐拉圖,那麽我們看似要把它先融成一個環,再把它拆開,但我們完全可以在融某一個點時就直接把它融開。所以ans+=入度大於2的點數,sum++。
對於其他情況,我們由於只需要把它們融成鏈,所以,ans+=入讀大於2的點數,sum+=入讀為單數的點數/2。
在最後我們輸出ans+sum即可。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <map> #include <vector> #define N 1005 #define M 50005*2+1005 using namespace std; int n,m,zz,rd[M],a[M],zz2; struct ro { int to; int next; }road[100005]; void build(int x,int y) { zz++; road[zz].to=y; road[zz].next=a[x]; a[x]=zz; } vector<int> q1[M]; int dfn[M],low[M],st[M],top,zz3,zz4; bool rz[M],rd2[M]; void tar(int x) { zz4++; dfn[x]=low[x]=zz4; rz[x]=rd2[x]=1; top++;st[top]=x; for(int i=a[x];i>0;i=road[i].next) { int y=road[i].to; if(!rd2[y]) { tar(y); low[x]=min(low[x],low[y]); } else if(rz[y]) { low[x]=min(low[x],dfn[y]); } } if(dfn[x]==low[x]) { zz3++; int v; do{ v=st[top]; rz[v]=0; top--; q1[zz3].push_back(v); }while(dfn[v]!=low[v]); } } int main() { scanf("%d%d",&n,&m); zz2=n; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if(!x) { zz2++; x=zz2; } if(!y) { zz2++; y=zz2; } build(x,y),build(y,x); rd[x]++,rd[y]++; } n=zz2; for(int i=1;i<=n;i++) { if(rd[i]&&!rd2[i]) tar(i); } int ans=0,sum=0; for(int i=1;i<=zz3;i++) { int js1=0,js2=0; for(int j=0;j<q1[i].size();j++) { if(rd[q1[i][j]]%2)js1++; if(rd[q1[i][j]]>2)js2++; } if(zz3==1) { if(js1) { ans=js2+js1/2; } else ans=js2; break; } if(js1==0&&js2==0) { ans++; sum++; } else if(js1==0) { sum++; ans+=js2; } else { ans+=js2; sum+=js1/2; } } ans+=sum; printf("%d\n",ans); return 0; }
10.1 國慶節給祖國母親獻禮 NOIP 模擬題 第二題題解