生成树题目
作者:互联网
1486:【例题1】黑暗城堡
先用dijkstra求出1号房间到每个房间的单源最短路径存储到dis数组中。把树形城堡看作以1为根的有根树。由题,若x是y的根节点,x、y之间的通道长度为z,
则应该有:dis[y]=dis[x]+z。事实上,我们把满足题目要求的树结构,即对任意一对父子结点x、y都有上式成立的树结构,称为图的一棵最短路径生成树。
与Prim算法类似,统计有多少结点x满足dis[p]=dis[x]+e[x][p],让p与其中任意一个x相连都符合题目要求
最短路径生成树:对于任意一对父子结点x、y均满足dis[y]=dis[x]+e[x][y]的树结构称为图的一棵最短路径生成树;
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<cstdio> #include<queue> #include<map> #include<vector> #include<set> using namespace std; const int maxn=1010; const int INF=0x3fffffff; typedef long long LL;\ /* 先用dijkstra求出1号房间到每个房间的单源最短路径存储到dis数组中。把树形城堡看作以1为根的有根树。由题,若x是y的根节点,x、y之间的通道长度为z, 则应该有:dis[y]=dis[x]+z。事实上,我们把满足题目要求的树结构,即对任意一对父子结点x、y都有上式成立的树结构,称为图的一棵最短路径生成树。 与Prim算法类似,统计有多少结点x满足dis[p]=dis[x]+e[x][p],让p与其中任意一个x相连都符合题目要求 最短路径生成树:对于任意一对父子结点x、y均满足dis[y]=dis[x]+e[x][y]的树结构称为图的一棵最短路径生成树; */ LL dis[maxn]; LL num[maxn]; int vis[maxn]; struct node{ int to,val; node(int a,int b){ to=a;val=b; } }; vector<node> adj[maxn]; int n,m; int main(){ int x,y,z; scanf("%d %d",&n,&m); for(int i=0;i<m;i++){ scanf("%d %d %d",&x,&y,&z); adj[x].push_back(node(y,z)); adj[y].push_back(node(x,z)); } for(int i=1;i<=n;i++) dis[i]=INF; dis[1]=0; for(int i=1;i<=n;i++){ int u=-1,temp=INF; for(int j=1;j<=n;j++){ if(!vis[j]&&dis[j]<temp){ temp=dis[j]; u=j; } } if(u==-1) break; vis[u]=1; for(int j=0;j<adj[u].size();j++){ int diss=adj[u][j].val; int to=adj[u][j].to; if(!vis[to]){ if(dis[to]>dis[u]+diss){ dis[to]=dis[u]+diss; } } } } LL ans=1,mod=(1<<31)-1; for(int i=1;i<=n;i++){ for(int j=0;j<adj[i].size();j++){ int t=adj[i][j].to; if(dis[t]==dis[i]+adj[i][j].val) num[t]++; } } for(int i=1;i<=n;i++){ //cout<<num[i]<<endl; if(num[i]){ ans=(ans*num[i])%mod; } } printf("%lld\n",ans); return 0; }
1487:【例 2】北极通讯网络
题目的意思是求最小生成树的第k大的边的长度
k个村庄装上卫星设备后可以看成1个点,那么只需要求这(n-k+1)个点和(n-k)条边所构成的最小生成树
利用Kruskal算法,只需要进行(n-k)次操作,最后一次操作时加入生成树的边的权值就是所求的d
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<cstdio> #include<queue> #include<map> #include<vector> #include<set> using namespace std; const int maxn=1010; const int INF=0x3fffffff; typedef long long LL; //题目的意思是求最小生成树的第k大的边的长度 /* k个村庄装上卫星设备后可以看成1个点,那么只需要求这(n-k+1)个点和(n-k)条边所构成的最小生成树 利用Kruskal算法,只需要进行(n-k)次操作,最后一次操作时加入生成树的边的权值就是所求的d */ int n,k,m,fa[510],x[510],y[510]; struct node{ int a,b; double dis; }ed[250000]; double js(int ax,int ay,int bx,int by){ return sqrt(pow(ax-bx,2)+pow(ay-by,2)); } bool cmp(node a,node b){ return a.dis<b.dis; } int findf(int x){ if(x==fa[x]) return x; else return fa[x]=findf(fa[x]); } int num1; double res; void kruskal(){ for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int fa1=findf(ed[i].a); int fa2=findf(ed[i].b); if(fa1!=fa2){ fa[fa1]=fa2; num1++; if(num1==n-k){ res=ed[i].dis; return ; } } } } int main(){ scanf("%d %d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d %d",&x[i],&y[i]); } if(k==0) k=1; //别忘了这一个 if(k>=n) { printf("0.00\n"); return 0; } else{ m=1; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ ed[m].a=i; ed[m].b=j; ed[m].dis=js(x[i],y[i],x[j],y[j]); m++; } } m--; //细节呀!!!!!!!!! sort(ed+1,ed+m+1,cmp); kruskal(); printf("%.2lf\n",res); } return 0; }
1488:新的开始
需要加一个超级源点!!!!!加的超级源点与各个点的边权为建立收费站的价值
应该建一个虚拟源点,每个点i连向虚拟源点的边权为发电站费用v[ i ]
为什么呢..?因为虽然是双向边,但存边的时候只能单向存。
这就导致,从哪个点出发,会决定了,有的边加不加的进去。
于是...不能简简单单的取出发电站费用中最少的.
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<cstdio> #include<queue> #include<map> #include<vector> #include<set> using namespace std; const int maxn=1010; const int INF=0x3fffffff; typedef long long LL; //还是不太理解为什么要加一个超级源点的问题 int n; int mon[510]; int mp[510][510]; LL dis[510]; int vis[510]={0}; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>mon[i]; mp[i][1+n]=mon[i]; mp[1+n][i]=mon[i]; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>mp[i][j]; } } for(int i=1;i<=n+1;i++){ //超级源点也要加上 dis[i]=mp[1][i]; } LL ans=0; vis[1]=1; for(int i=1;i<=n;i++){ int u=-1,temp=INF; for(int j=1;j<=n+1;j++){ if(!vis[j]&&dis[j]<temp){ temp=dis[j]; u=j; } } if(u==-1) break; vis[u]=1; ans+=dis[u]; for(int j=1;j<=n+1;j++){ if(!vis[j]&&j!=u&&dis[j]<mp[u][j]){ dis[j]=mp[u][j]; } } } cout<<ans<<endl; return 0; }
标签:题目,int,LL,生成,510,include,dis 来源: https://www.cnblogs.com/shirlybaby/p/12558967.html