ディレクトリ
グラフ理論
最小スパニングツリー
$ N $市は、$ M $バーが道路を修復することができ、各道路は、都市の接続を行うための$ w_i $の修理費用、$ N $、必要最小限のコストを持っていますか?
これは、ツリーを形成$ N-1 $エッジの最小値が必要です。
##クラスカルのアルゴリズムは、証明します
誘導を行うための$ N $のポイントと、図の上部には、オーダーのいずれかのグラフのための$クラスカル$の$ n $のアルゴリズムが適用されることを証明
誘導ベース
$ N = 1 $は、明らかに最小全域木を見つけるために
誘導プロセス
例
アイデアは$ w_i $右側用サイドを構築するために、各ポイントにスーパーソースを構築し、その後、最小スパニングツリーを実行することです
製品は共同素数の数に分けることができます方法を示し
Iあまりにも料理、書きません
最小スパニングツリーの最大の右側のパスポイントを求めます
int f[N][20]; //i的第2^j祖先
int mn[N][20]; //i往上跳2^j祖先所经过的边的最小值
int query(int u,int v) {
int ans=inf;
if(dep[u]>dep[v]) swap(u,v);
for(int i=0,k=dep[v]-dep[u];i<=LG[k];++i)
if(k>>i&1) {
ans=min(ans,mn[v][i]);
v=f[v][i];
}
if(u==v) return ans;
for(int i=LG[dep[u]];i>=0;--i)
if(f[u][i]!=f[v][i]) {
ans=min(ans,min(mn[u][i],mn[v][i]));
u=f[u][i],v=f[v][i];
}
ans=min(ans,min(mn[u][0],mn[v][0]));
return ans;
}
クラスカル復興ツリー
最短
SPFAの没収リング
queue<int> q;
bool inq[N];
int dis[N], len[N];
bool spfa() { //返回值为true表示有负环 否则没有负环
fill(dis+1,dis+n+1,inf);
dis[1]=0,len[1]=1;
q.push(1);
inq[1]=true;
while(!q.empty()) {
int u=q.front() ; q.pop();
inq[u]=false;
for(int i=0;i<e[u].size();++i) {
int v=e[u][i];
int w=W[u][i];
if(dis[u]+w<dis[v]) {
dis[v]=dis[u]+w;
len[v]=len[u]+1;
if(len[v]>=n) return true;
if(!inq[v]) q.push(v),inq[v]=true;
}
}
}
return false;
}
地図の建物のスキル
仮想点を追加することによって、問題は、形質転換さ等
等辺の数を減少させる目的を達成するように。
サン作業、長時間露光
トポロジカルソート
DAG $は非環式有向グラフ$で)ソートする直線状のグラフに、我々の頂点、$ Vの任意の頂点$ U $ $有向枝$(U、V)$、のためのものであるようにあなたは、のの$ V $の前の$ U $を持っていることがあります。
//拓扑排序 O(n^2)
int ind[N]; //每个点的入度
int seq[N],cnt; //求出的拓扑序
bool vis[N];
bool toposort() { //有环返回false
while(true) {
if(cnt==n) return true;
int k=0;
for(int i=1;i<=n;++i)
if(!vis[i]&&ind[i]==0) {
k=i; break;
}
if(k==0) return false;
seq[++cnt]=k; vis[k]=true;
for(int i=0;i<e[k].size();++i) {
int u=e[k][i];
--ind[u];
}
}
}
キューの最適化
$のO(N + M)$
//拓扑排序 O(n+m)
queue<int> q; //q中维护入度为0的点
int ind[N],seq[N],cnt;
bool toposort() { //有环返回false
for(int i=1;i<=n;++i)
if(!ind[i]) q.push(i);
while(!q.empty()) {
int u=q.front(); q.pop();
seq[++cnt]=u;
for(int i=0;i<e[u].size();++i) {
int v=e[u][i];
--ind[v];
if(ind[v]==0) q.push(v);
}
}
return cnt==n;
}
tarjian
int dfn[N],low[N],dfsclock;
int s[N],top;
int cnt; //当前联通块的编号
int bl[N]; //bl[i]表示i所在的强联通分量编号
vector<int> scc[N]; //scc[i]中存储编号为i强联通分量中的所有点
void dfs(int u) {
low[u]=dfn[u]=++dfsclock;
s[++top]=u;
for(int i=0;i<e[u].size();++i) {
int v=e[u][i];
if(dfn[v]) low[u]=min(low[u],dfn[v]);
else {
dfs(v);
low[u]=min(low[u],low[v]);
}
}
if(low[u]==dfn[u]) {
++cnt;
int v=s[top];
while(v!=u) {
bl[v]=cnt;
scc[cnt].push_back(v);
v=s[--top];
}
bl[u]=cnt;
scc[cnt].push_back(u);
}
}
##ポイント還元
強連結成分に点が大きなポイントであるかのように、次に、図は、非巡回グラフ(DAG $ $)を指向になることができ、その後、再帰を容易にするもの
微分制約
書き込み後は、それは、私は、これはマップを設定し、右不平等であることを感じて...私も苦手
ツリーカラー/グループツリーリング
私たちは、木が最も簡単な無向グラフの接続であることを知っています。
任意の2点間の唯一のパスがツリーにあります
襟の木/木のシクロアルキル基:ツリーカトー側。
$、$ uは、次に前に作られた一面を設けプラス$ている(U、V)はV $、このエッジとの間のパスは、このパスと環を形成し、このエッジの添加後に存在します。
これはまた、リングの一方のみが形成されています
リング上の各点がルートであると思われるように、我々は、中央のリングのビューに置くことができます。
場所は、リングを見つけることは非常に重要です
同様のアプローチの$ noip2016情報転送$
ツリーリングベースリングをゲット
リングの手順を探します:
1.ツリーの$ DFS $として、スポットスタートを見つけ、各ノードのアクセスタイムスタンプの$ DFN $を記録する自由
そこ2の$のDFS $プロセスは、それらの小さな点よりもエッジが、これは1つのプラス側と見なすことができるための$ DFN $の点であろう。このエッジ$を記録(u、v)は$
3.暴力は$ U $と$ V $はそのポイントを記録した後、それぞれのルートまで移動しましょう。
4.彼らは、すなわち環を形成LCA $> V-の間にLCA $ + $すべての点の間のすべてのポイントそれら$ LCA $、$ U->の最深点となっています。
//求基环树中的环 方法一
int fa[N]; //f[i]为i在搜索树中的父亲结点
bool in[N],vis[N]; //表示i是否在环中
int cir[N],cnt;
int x,y;
void dfs(int u,int f) { //f为u的父亲结点
fa[u]=f; vis[u]=1;
for(int i=0 ;i<e[u].size();++i) {
int v=e[u][i];
if(v==f) continue;
if(vis[v]) x=u,y=v;
else dfs(v,u);
}
}
void solve() { //x到y一定是返祖边
dfs(1,0);
while(x!=y) {
cir[++cnt]=x;
x=fa[x];
}
cir[++cnt]=y;
}
//方法二
queue<int>q;
int deg[N],n;
void solve()
{
for(int i=1;i<=n;++i) in[i]=1;
for(int i=1;i<=n;++i)
if(deg[i]==1) q.push(i);
while(!q.empty())
{
int u=q.front();
q.pop();
int[u]=0;
for(int i=0;i<e[u].size();++i)
{
int v=e[u][i];
deg[v]--;
if(deg[v]==0) q.push(v);
}
}
int u;//u作为环的起点
for(u=1;u<=n;++u)
if(in[u]) break;
int v=u,las=0;//把u放环里
do{
cir[++cnt]=v;
int k;
for(i=0;i<e[v].size();++i)
{
k=e[v][i];
if(in[k] && k!=las) break;
}
la
v=k;
}while(v!=u)
}
オイラー
全ての頂点のすべてのエッジを介してライン唯一つの通路を描くことによってオイラー経路と呼ばれます。
全ての頂点のすべてのエッジを介してライン唯一つのループを描くことによってオイラーと呼ばれています。
図オイラーオイラー図を有すると称される。
オイラーを有する図通路は、半オイラー図と呼ばれます。
図の時と同様にそこに定義することができます。
$ G $はオイラー場合にのみ$ G $は、通信の頂点奇数とされていない場合です。
$ G $半オイラー場合と$ $ Gが正確に2奇数度の頂点がある場合にのみ。
証明書:
そして、奇数の頂点の通信は=>リングがあってはなりません
その後、我々は、リング上のエッジを削除する通信の残りと依然として図ない奇数の頂点を満たしています
接続リングは共通点であってもよいし、一緒に入れなければ
スネアループアルゴリズム
$のDFS $検索、パスのバックトラックを記録し、その後、ダウン行くことができない(エッジを再利用することはできませんが、ポイントの後に繰り返すことができる)戻ってくる、バックトラックは側の明確なマークはないが、最終的にパスがオイラーで見つけます。
それぞれの側が訪問したかどうか$ VIS $アレイレコードに番号をEdgeに
//欧拉回路 圈套圈算法
struct edge
{
int v,nex,id;
};
bool vis[N];
int s[N],top;
int seq[N],cnt;
void dfs(int u)
{
s[++top]=u;
for(int i=head[u];i;i=e[i].nex)
{
if(vis[e[i].id]) continue;
vis[e[i].id]=true;
dfs(e[i].v);
}
--top;
seq[++top]=e[i].v;
}