Day3 生成樹專題
文章目錄
A. UVALive 6437 Power Plant
題目
程式碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct rec
{
int x,y,z;
}edge[maxn*maxn];
int fa[maxn];
inline int get(int x)
{
if (fa[x]==x) return x;
return fa[x]=get(fa[x]);
}
inline bool cmp(rec a,rec b)
{
return a.z<b.z;
}
int main()
{
int t;read(t);
for (int cnt=1;cnt<=t;++cnt)
{
int n,m,k,f,ans=0;
read(n);read(m);read(k);
for (int i=1;i<=n;++i)
fa[i]=i;
read(f);
for (int i=2;i<=k;++i)
{
int x;read(x);
fa[x]=f;
}
for (int i=1;i<=m;++i)
{
read(edge[i].x);
read(edge[i].y);
read(edge[i].z);
}
sort(edge+1,edge+m+1,cmp);
for (int i=1;i<=m;++i)
{
int x=edge[i].x;
int y=edge[i].y;
if (get(x)==get(y)) continue;
fa[fa[x]]=fa[y];
ans+=edge[i].z;
}
printf("Case #%d: %d\n",cnt,ans);
}
return 0;
}
B. POJ 2349 UVA 10369 Arctic Network
題目
程式碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct rec
{
int fr,to;
double z;
}edge[maxn*maxn];
int fa[maxn],dx[maxn],dy[maxn];
inline int get(int x)
{
return fa[x]==x?x:fa[x]=get(fa[x]);
}
inline void combine(int x,int y)
{
int xx=get(x),yy=get(y);
if (xx!=yy) fa[xx]=yy;
}
inline bool cmp(rec a,rec b)
{
return a.z<b.z;
}
int main()
{
int t;read(t);
while (t--)
{
int m,n,len=0,tot=0;
double ans=0.00;
read(m);read(n);
for (int i=1;i<=n;++i)
{
fa[i]=i;
read(dx[i]);read(dy[i]);
}
for (int i=1;i<n;++i)
for (int j=i+1;j<=n;++j)
edge[++len].fr=i,edge[len].to=j,
edge[len].z=sqrt(double((dx[i]-dx[j])*(dx[i]-dx[j]))
+double((dy[i]-dy[j])*(dy[i]-dy[j])));
sort(edge+1,edge+len+1,cmp);
for (int i=1;i<=len;++i)
{
if (get(fa[edge[i].fr])!=get(fa[edge[i].to]))
{
combine(edge[i].fr,edge[i].to);
++tot;
ans=edge[i].z;
}
if (tot==n-m) break;
}
printf("%.2lf\n",ans);
}
return 0;
}
C. BZOJ 1232: [Usaco2008Nov]安慰奶牛cheer
題目
程式碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct rec
{
int x,y,z;
}edge[maxn<<1];
int fa[maxn],c[maxn],ans=0x3f3f3f3f,tot;
inline int get(int x)
{
if (x==fa[x]) return x;
return fa[x]=get(fa[x]);
}
inline bool cmp(rec a,rec b)
{
return a.z<b.z;
}
int main()
{
int n,p;read(n);read(p);
for (int i=1;i<=n;++i)
{
read(c[i]);
ans=min(ans,c[i]);
fa[i]=i;
}
for (int i=1;i<=p;++i)
{
int x,y,z;
read(x);read(y);read(z);
z=(z<<1)+c[x]+c[y];
edge[i].x=x,edge[i].y=y,edge[i].z=z;
}
sort(edge+1,edge+p+1,cmp);
for (int i=1;i<=p;++i)
{
int x=get(edge[i].x);
int y=get(edge[i].y);
if (x!=y)
{
fa[x]=y;
++tot;
ans+=edge[i].z;
}
if (tot==n-1) break;
}
printf("%d\n",ans);
return 0;
}
D. UVA1151 Buy or Build
題目
程式碼
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1e3+5;
const int maxm=5e5+5e2;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct Node
{
int x,y;
}node[maxn];
struct rec
{
int x,y,z;
bool operator < (const rec &a) const
{
return z<a.z;
}
}edge[maxm];
int fa[maxn],cost[10];
int n,q,num;
vector<int>g[10];
inline int get(int x)
{
if (fa[x]==x) return x;
return fa[x]=get(fa[x]);
}
inline int combine(int x,int y)
{
int xx=get(x),yy=get(y);
if (xx==yy) return false;
fa[xx]=yy;
return true;
}
int Kruskal()
{
int ans=0,cnt=0;
for (int i=0;i<num;++i)
{
if (combine(edge[i].x,edge[i].y))
{
ans+=edge[i].z;
++cnt;
}
if (cnt==n-1) break;
}
return ans;
}
int main()
{
// int t;read(t);
// while (t--)
// {
read(n);read(q);
for (int i=0;i<q;++i)
{
g[i].clear();int number;
read(number);read(cost[i]);
for (int j=0;j<number;++j)
{
int x;read(x);
g[i].push_back(x);
}
}
for (int i=1;i<=n;++i)
{
read(node[i].x);
read(node[i].y);
}
for (int i=1;i<=n;++i)
for (int j=i+1;j<=n;++j)
edge[num].x=i,edge[num].y=j,
edge[num++].z=(node[i].x-node[j].x)*(node[i].x-node[j].x)+(node[i].y-node[j].y)*(node[i].y-node[j].y);
sort(edge,edge+num);
for (int i=0;i<=n;++i)
fa[i]=i;
int ans=Kruskal();
for (int i=0;i<(1<<q);++i)
{
for (int k=0;k<=n;++k)
fa[k]=k;
int all=0;
for (int j=0;j<q;++j)
{
if (!((i>>j)&1)) continue;//if (1!=(i>>j))
all+=cost[j];
for (int k=1;k<g[j].size();++k)
combine(g[j][k],g[j][0]);
}
ans=min(ans,all+Kruskal());
}
printf("%d\n",ans);
// if (t) puts("");
// }
return 0;
}
E. POJ 3522 Slim Span
題目
題意
給出一個圖,若圖連通,則求最大邊與最小邊差值最小的生成樹,輸出最小差值。否則輸出-1。
題解
其實就是求邊權差值最小的生成樹。
1.首先我們看一下資料範圍,,很小,所以我們就可以直接列舉最小邊。
2.接著跑最小生成樹,就是瓶頸生成樹,因為最小生成樹有一個很重要的性質:在構造生成樹時有可能選擇不同的邊,但最小生成樹的權是唯一的!所以在用kruskal演算法時第一次加入的必然是最小生成樹的最小邊權值,最小邊確定後,==最小生成樹的最大邊的權值是所以生成樹中最小的,==即為瓶頸生成樹。
3.然後更新答案即可。
程式碼
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=2e5+10;
char buf[1<<15],*fs,*ft;
inline char getc(){return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++;}
inline int read()
{
int num=0,f=1;char ch=getchar();
while (!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while (isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48), ch=getchar();
return num*f;
}
struct rec
{
int x,y,z;
}edge[maxn];
int fa[maxn],ans;
inline bool operator < (rec a,rec b)
{
return a.z<b.z;
}
inline int get(int x)
{
if (x==fa[x]) return x;
return fa[x]=get(fa[x]);
}
int main()
{
while (1)
{
int n=read(),m=read(),i=0;
if (!n && !m) break;
if (n==1)
{
puts("0");
exit(0);
}
for (i=1;i<=m;++i)
edge[i].x=read(),edge[i].y=read(),edge[i].z=read();
sort(edge+1,edge+m+1);
ans=edge[m].z;//差值初始化
for (int k=1;k<=m;++k)//以k為最小邊進行列舉
{
int sum=0;//最小生成樹的邊數
for (i=1;i<=n;++i)//生成樹初始化
fa[i]=i;
for (i=k;i<=m;++i)//求最小生成樹
{
int x=get(edge[i].x);
int y=get(edge[i].y);
if (x==y) continue;
fa[x]=y;
++sum;
if (sum==n-1)//已構成一個最小生成樹(從定義出發)
{
ans=min(ans,edge[i].z-edge[k].z);//最大邊減去最小邊
break;
}
}
if (i==m+1) break;
}
if (ans==edge[m].z)//ans未經過改變,說明此圖未連通
puts("-1");
else
printf("%d\n",ans);
}
return 0;
}
F. UVA10816 Travel in Desert
題目
題解
首先,這是一道 生成樹最短路 的題。
程式碼
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1e4+5;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct MST
{
int fr,to;
double tem,len;
friend bool operator < (const MST &a,const MST &b)
{
return a.tem<b.tem;
}
}tree[maxn<<1];
int ver[maxn<<1],Next[maxn<<1],head[maxn],len,num;
double edge[maxn<<1];
inline void add(int x,int y,double z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
inline void insert(int x,int y,double tem,double dis)
{
tree[++num].fr=x,tree[num].to=y,tree[num].len=dis,tree[num].tem=tem;
}
int fa[maxn],n,m,s,t;
inline int get(int x)
{
return fa[x]==x?x:fa[x]=get(fa[x]);
}
struct HeapNode
{
int u;//點
double d;//距離
friend bool operator < (const HeapNode &a,const HeapNode &b)
{
return a.d>b.d;
}
};
priority_queue<HeapNode> q;
vector<int> path;
double maxtem,dist[maxn];
bool vis[maxn];
inline void heap_dijkstra()
{
for (register int i=1;i<=n;++i)
dist[i]=0x3f3f3f3f,vis[i]=0,fa[i]=0;
dist[s]=0;
q.push((HeapNode){s,dist[s]});
while (!q.empty())
{
int x=q.top().u;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
double z=edge[i];
if (dist[y]>dist[x]+z)
{
dist[y]=dist[x]+z;
fa[y]=x;//再跑最短路的同時,用並查集確定x與y之間的關係,即x是y的父親
q.push((HeapNode){y,dist[y]});
}
}
}
register int x=t;
path.clear();
while (x!=s)//從終點出發,一直在樹上遍歷到起點,就剛好把路徑加入到path[]中
{
path.push_back(x);
x=fa[x];
}
path.push_back(s);
for (register int i=path.size()-1;i>=1;--i)
printf("%d ",path[i]);
printf("%d\n",path[0]);
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
num=len=0;maxtem=0;
memset(head,0,sizeof(head));
memset(fa,0,sizeof(fa));
read(s);read(t);
register double te,w;
for (register int i=1,fr,to;i<=m;++i)
{
read(fr);read(to);
scanf("%lf%lf",&te,&w);
insert(fr,to,te,w);
}
for (register int i=1;i<=n;++i)
fa[i]=i;
sort(tree+1,tree+m+1);
for (register int i=1;i<=m;++i)
{
register int x=get(tree[i].fr),y=get(tree[i].to);
if (x!=y)
{
fa[x]=y;
maxtem=max(maxtem,tree[i].tem);
if (get(s)==get(t)) break;
}
}
for (int i=1;i<=m;++i)
{
if (tree[i].tem>maxtem) break;;
add(tree[i].fr,tree[i].to,tree[i].len);
add(tree[i].to,tree[i].fr,tree[i].len);
}
heap_dijkstra();
printf("%.1f %.1f\n",dist[t],maxtem);
}
return 0;
}
G. POJ 1639 Picnic Planning 最小度數限制生成樹
題目
題解
假設Park的停車數沒有限制,那麼這題就是一道最小生成樹了。
但是本題限制Park的停車數不能超過k,把Park看做根節點記為V0,那麼就是說它的度數不能超過k。
得到一棵k度限制生成樹的步驟:
-
忽略根節點做一次kruskal,此時得到的是一個森林,包含了m個最小生成樹。
-
對於每一顆最小生成樹,選擇其中離根節點最近的點,向根節點連一條邊,此時得到了一棵m度的最小生成樹。
-
由m度生成樹得到m+1度生成樹:
(1). 用dp預處理出當前生成樹中從V0到點i的路徑上與V0無關聯的權值最大的邊,記為,該邊的兩端點記為和。(及程式碼中的dfs函式預處理)
(2). 對於一個不在生成樹中的邊, 如果將該邊加入生成樹中,則一定會得到一個環。
此時我們刪掉環中權值最大的邊,即(1)中預處理得到的,得到一棵m+1度的生成樹。(3). 對於(2)列舉每一個v,記,使minnum得到最小值的點就是這次選擇的點。連線,刪去。
-
重複步驟3直到得到一棵k度限制生成樹。本題要求度數不超過k,所以在某一步中,minnum>=0,就可以輸出答案了。
關於的含義:
為在從m度生成樹得到m+1度生成樹的過程中,選擇一個點v(連線,刪去)可以得到的最大利益,即生成樹的值最多可以減少多少。
為負數,表示選擇點v可以生成樹的值減少,那麼使minnum最小的點就是可以使生成樹的值減少最多的點,這次我們便選擇它。
如果>=0,說明得到m+1度生成樹不會獲得任何利益,就不用繼續下去,直接輸出答案即可。
- 關於最小度數限制生成樹詳情參考2004國家集訓隊汪汀的論文。摘自accepoc。
程式碼
友情提示:想在洛谷上過這道題,我註釋掉的語句就必須加上,少一句就可能是WA或TLE。 ̄ω ̄=
/*****************************************
Memory: 156K Time: 16MS
Language: C++ Result: Accepted
*****************************************/
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=35,inf=0x3f3f3f3f;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct mst
{
int x,y,z,next;
inline bool operator < (const mst a) const
{
return z < a.z;
}
}f[maxn<<1];
int k,tot,ans,fa[maxn],a[maxn][maxn],d[maxn],v[maxn];
map<string,int>m;
vector<mst>e;
bool b[maxn][maxn];
inline int get(int x)
{
if (fa[x]==x) return x;
return fa[x]=get(fa[x]);
}
inline void dfs(int x,int o)
{
for (int i=2;i<=tot;++i)
{
if (i==o || !b[x][i]) continue;
if (f[i].z==-1)
{
if (f[x].z>a[x][i]) f[i]=f[x];
else
f[i].x=x,f[i].y=i,f[i].z=a[x][i];
}
dfs(i,x);
}
}
int main()
{
// int t;read(t);
// while (t--)
// {
int n;read(n);
// ans=0;
memset(a,0x3f,sizeof(a));
memset(d,0x3f,sizeof(d));
// memset(f,0,sizeof(f));
// memset(v,0,sizeof(v));
// memset(b,0,sizeof(b));
// m.clear(),e.clear();
m["Park"]=tot=1;
for (int i=0;i<maxn;++i)
fa[i]=i;
for (int i=1;i<=n;++i)
{
mst w;
string s1,s2;
cin>>s1>>s2;read(w.z);
w.x=m[s1]?m[s1]:(m[s1]=++tot);
w.y=m[s2]?m[s2]:(m[s2]=++tot);
e.push_back(w);
a[w.x][w.y]=a[w.y][w.x]=min(a[w.x][w.y],w.z);
}
read(k);
sort(e.begin(),e.end());
for (unsigned int i=0;i<e.size();++i)
{
if (e[i].x==1 || e[i].y==1) continue;
int x=get(e[i].x),y=get(e[i].y);
if (x!=y)
{
fa[y]=x;
b[e[i].x][e[i].y]=b[e[i].y][e[i].x]=1;
ans+=e[i].z;
}
}
for (int i=2;i<=tot;++i)
if (a[1][i]!=inf)
{
int root=get(i);
if (d[root]>a[1][i])
d[root]=a[1][v[root]=i];
}
for (int i=1;i<=tot;++i)
if (d[i]!=inf)
{
--k;
b[1][v[i]]=b[v[i]][1]=1;
ans+=a[1][v[i]];
}
while (k--)
{
memset(f,-1,sizeof(f));
f[1].z=-inf;
for (int i=1;i<=tot;++i)
if (b[1][i])
f[i].z=-inf;//QWQ
dfs(1,-1);
int o,w=-inf;//QAQ
for (int i=2;i<=tot;++i)
if (w<f[i].z-a[1][i])
w=f[i].z-a[1][o=i];
if (w<=0) break;
b[1][o]=b[o][1]=1;
b[f[o].x][f[o].y]=b[f[o].y][f[o].x]=0;
ans-=w;
}
printf("Total miles driven: %d\n",ans);
// if (t) puts("");
// }
return 0;
}
相關文章
- 專題六 最小生成樹【Kuangbin】
- 最小生成樹專項
- 樹專題
- 字典樹專題
- 一類生成樹計數問題。
- 【題解】Solution Set - NOIP2024集訓Day3 權值線段樹、動態開點、主席樹
- NOIP 複習題之最小生成樹
- 一些“最小生成樹”板題
- LeetCode刷題記錄——day3LeetCode
- 生成樹協議與多生成樹協議協議
- 生成樹Toolkit
- 勢能線段樹專題
- python 使用 最大生成樹 解決 營救問題Python
- STP生成樹協議和MSTP多生成樹協議協議
- 最小生成樹
- 前端必會演算法 - 最小生成樹問題前端演算法
- 【演算法學習筆記】生成樹問題探究演算法筆記
- Day3
- 【模板】最小生成樹
- 生成樹演算法演算法
- 最小度限制生成樹
- STP(生成樹協議)協議
- STP生成樹協議協議
- 【模板】最小生成樹-kruskal
- 圖論 最小生成樹圖論
- STP--生成樹協議協議
- 快速生成樹原理詳解
- 圖的最小生成樹
- 生成樹與鏈路聚合
- 【圖論】最小生成樹圖論
- 「種樹專業戶」“樹”業有專攻
- 第五章 字串專題 ---------------- 5.11 題解:最短摘要的生成字串
- Prim 最小生成樹 圖解圖解
- prim 樸素 最小生成樹
- markdown樹形結構生成工具
- Apache Spark Day3ApacheSpark
- Laravel 框架 day3Laravel框架
- 決策樹模型(3)決策樹的生成與剪枝模型