BZOJ.PA2009 Cakes(三元環)

BZOJ.PA2009 Cakes(三元環)

思路:三元環的裸題。第一次寫還是稍微整理一下求三元環的思路。


1.無向圖(無重邊,無自環)轉化爲有向無環圖。

轉化的方法:對於任意邊edge(u,v),edge(u,v),度數大的結點指向度數小的結點,若度數相同,則編號小的結點指向編號大的結點。

用表達式即:if(deg[u]<deg[v]deg[u]==deg[v]&&u>v)swap(u,v)if(deg[u]<deg[v]||deg[u]==deg[v]\&\&u>v)\quad swap(u,v)

e[u].push_back(v).e[u].push\_back(v).變爲有向邊。


2.接下來就是遍歷每個結點看能否形成三元環。

對於結點ii的所有相鄰結點uu打上標記,再對每個uu遍歷它的相鄰結點vv,若vvii給的標記,說明是一個三元環。

說明:這裏每個三元環只會被記錄一次。

時間複雜度:O(mm)O(m\sqrt{m})


簡單證明下時間複雜度:

顯然我們考慮一條邊uvu\rightarrow v對時間的貢獻是outvout_v,

則總時間複雜度爲:i=1m=outvi\sum\limits_{i=1}^m=out_{v_i}

outvout_v是結點vv的出度。

顯然分兩種情況。

deg(v)mdeg(v)\leq\sqrt{m}時,因爲outvdeg(v)out_v\leq deg(v),所以時間複雜度是outv=mout_v=\sqrt{m}

dge(v)>(m)dge(v)>\sqrt{(m)}時,因爲圖的總度數是O(m)O(m)的,所以度數>m>\sqrt{m}的結點至多有O(m)O(\sqrt{m})個,而vv只能連向度數不小於它的結點,所以時間複雜度:outv=mout_v=\sqrt{m}.

綜上:總時間複雜度:i=1m=outvi=mm\sum\limits_{i=1}^m=out_{v_i}=m\sqrt{m}.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
int n,m,deg[N],vis[N],val[N];
vector<int>e[N];
struct node{
	int u,v;
}a[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&val[i]);
	for(int i=1;i<=m;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		deg[u]++,deg[v]++;
		a[i]={u,v};
	}
	for(int i=1;i<=m;i++){
		int u=a[i].u,v=a[i].v; 
		if(deg[u]>deg[v]||deg[u]==deg[v]&&u>v) swap(u,v);	//無向圖轉有向無環圖. 
		e[u].push_back(v);
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		for(auto v:e[i]) vis[v]=i;
		for(auto u:e[i])
			for(auto v:e[u])
				if(vis[v]==i) ans+=max({val[u],val[v],val[i]}); 
	}
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章