【NOIP2018模擬】電壓機制

【問題描述】

科學家在“無限神機”(Infinity Machine)找到一個奇怪的機制,這個機制有N 個元件,有M條電線連接這些元件,所有元件都是連通的。兩個元件之間可能有多條 電線連接。 科學家對這些元件可以任意地設置爲“高電壓”和“低電壓”兩種模式,如果一 條電線的一端爲高電壓,另一端爲低電壓,這條電線就會產生電流。 爲了安全的研究“無限神機”,科學家需要找到一條電線,將它的兩端設爲相同 的電壓,並且除選擇的這條電線外,其它所有電線都有電流(否則就沒有研究的價值 了)。 有多少條電線滿足這樣的條件?

【輸入格式】

從文件 voltage.in 中讀入數據。 輸入的第一行包含兩個正整數 n, m ,表示元件數和電線數。 接下來 m 行,每行兩個整數 u, v,表示元件 u 和元件 v 有一條電線連接

【輸出格式】

輸出到文件 voltage.out 中。 輸出一個整數,表示有多少條電線滿足條件。

【樣例1輸入】

4 5 1 2 1 3 1 4 2 4 3 4

【樣例1輸出】

1

【樣例1說明】

只有電線(1,4)滿足  

【樣例2輸入】

4 4 1 2 2 3 3 2 4 3

【樣例2輸出】

2

【樣例2說明】

電線(1,2)和(3,4)滿足要求

【數據範圍】

對於10%的數據,滿足 n ≤ 1000 , m ≤ 2000

對於另外10%的數據,滿足 m = n

對於另外35%的數據,滿足 m ≤ n + 100

對於100%的數據,滿足 2 ≤ n ≤ 100000 , 1 ≤ m ≤ 200000

題目翻譯

對一個無向圖,尋找有多少條邊滿足:刪去這條邊後,使圖爲二分圖,且這條邊的端點不在二分圖的同一側

二層翻譯

 尋找有多少條邊滿足:圖中所有奇環都包含這條邊,且這條邊不屬於任何偶環

直接說100%數據的做法

建一棵DFS樹,通過返祖邊找環

對每個點記錄一個cnt,當返祖邊u->v形成奇環(染色法判斷)時cnt[u]++,cnt[v]--,偶環時反過來,並確定這條邊一定不能被選。這樣以後u的子樹內所有的cnt之和就表示了u->fa這條邊被多少奇環包含(差分前綴和思想)。

code

#include<bits/stdc++.h>//正式比賽別亂用
using namespace std;
struct mzls
{
	int to,id;
}as;
vector<mzls>g[100005];
bool c[100005],f[100005],f1[200005];//注意邊和點不同的範圍
int cnt[200005],tot[200005],n,m,ans,t1;
inline void dfs(int u)
{
	f[u]=1;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i].to,d=g[u][i].id;
		if(f1[d])
			continue;
		f1[d]=1;
		if(f[v]&&c[v]==c[u])//顏色相同時爲奇環
		{
			t1++;//記錄圖中所有的奇環
			cnt[u]++;
			cnt[v]--;
			tot[d]++;
			continue;
		}
		if(f[v])
		{
			cnt[v]++;
			cnt[u]--;
			tot[d]--;//這裏被減了以後d這條邊永遠不可能被選
			continue;
		}
		c[v]=!c[u];//交叉染色
		dfs(v);
		tot[d]+=cnt[v];
		cnt[u]+=cnt[v];//從下往上傳
	}
}
int main()
{
	//freopen("voltage.in","r",stdin);
	//freopen("voltage.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		as.to=y,as.id=i;//每條邊單獨記錄id,因爲兩點之間可以有重邊
		g[x].push_back(as);
		as.to=x;
		g[y].push_back(as);
	}
	dfs(1);
	for(int i=1;i<=m;i++)
		if(tot[i]==t1)
			ans++;
	printf("%d\n",ans);
}

 

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