BUAA OJ 382 中世界的Thor
2017-07-25 18:06
120 查看
BUAA OJ 382 中世界的Thor
题目描述
时间限制: 1000 ms 内存限制: 65536 kb好久没见Thor了哈,他去了哪里呢?
他去了中世界,在给那里的城镇修铁路。
中世界铁路公司要求Thor建设这样一条铁路: 在连同所有城镇的前提下,使得铁路的总长最短。
这对于Thor自然不是难事咯——不就是求一个最小生成树嘛~
然而Thor是一个贪心的工程师,他想在这其中做一些手脚,使得既满足铁路的布局是一棵生成树,其费用又比最小生成树要大上那么一丢丢,这样他便可以从预算与实际的差价之中收取一定的私利。
然而Thor这样做还是有风险的,一旦被发现后果很严重。于是谨慎起见,他准备找到这样一个方案,在既使得布局是一颗生成树,又使得其费用是除最小生成树以外最小的费用。现在这个事情被交给了你。
输入
多组数据。对于每一组数据,第一行有两个正整数n和m,表示有n个城镇以及m条可以铺设的铁路路线。(1≤n≤300)
接下来m行,每行有三个正整数x、y、w,表示城镇x到城镇y之间可以铺设一条长度为w的铁路。城镇编号从1开始。 (1≤c≤100)
数据保证没有重边和自环,同时保证图中有环存在。
输出
对于每一组数据,输出得到的生成树的边长之和。输入样例
3 3 1 2 1 2 3 2 1 3 3
输出样例
4
解题思路
求次小生成树代码
方法一
先求出最小生成树,然后去掉最小生成树上的一条边,再求这个去掉了一条边的图最小生成树,这些最小生成树中的权值之和最小者(而且顶点必须仍然是n个的)就是原图的次小生成树。O(N3)O(N3)#include<cstdio> #include<algorithm> #include<vector> #include<cstring> using namespace std; typedef struct edge{ int u,v,w; edge(int x,int y,int ww):u(x),v(y),w(ww){} }edge; bool cmp(edge a,edge b) { return a.w<b.w; } int a[305][305]; int uf[305]; bool use[305][305]; int find(int num) { if(uf[num]==num)return num; return uf[num]=find(uf[num]); } void connect(int x,int y) { uf[find(y)]=x; } int krus(int n) { int edgeNum=1; memset(use,0,sizeof(use)); vector<edge>vec; vec.reserve(100000); for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) if(a[x][y]&&x<y) vec.push_back(edge(x,y,a[x][y])); sort(vec.begin(),vec.end(),cmp); int sum=0,cnt=0; for(int i=1;i<=300;i++) uf[i]=i; for(int i=0;i<vec.size()&&cnt<n-1;i++) if(find(vec[i].v)!=find(vec[i].u)){ sum+=vec[i].w;connect(vec[i].u,vec[i].v);++cnt; use[vec[i].u][vec[i].v]=use[vec[i].v][vec[i].u]=true; ++edgeNum; } return edgeNum==n?sum:-1; } int main() { int n,m,x,y,w; while(~scanf("%d%d",&n,&m)) { memset(a,0,sizeof(a)); for(int i=0;i<m;i++) { scanf("%d%d%d",&x,&y,&w); a[x][y]=w;a[y][x]=w; } int sum=krus(n); vector<edge>mst;mst.reserve(305); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(use[i][j]) if(i<j) mst.push_back(edge(i,j,a[i][j])); int t,tst,max=99999999; bool flag=false; for(int i=0;i<mst.size();i++){ t=mst[i].w; a[mst[i].u][mst[i].v]=a[mst[i].v][mst[i].u]=0; tst=krus(n); if(tst<max&&tst!=-1) max=tst; a[mst[i].u][mst[i].v]=a[mst[i].v][mst[i].u]=t; } printf("%d\n",max); } }
方法二
求出最小生成树上任意两点的最短边,任意加入一条边之后必然成环,这时去掉这两点之间的最短边就会得到一棵树,这些树中权值最小的就是次小生成树。O(n2)O(n2)#include <algorithm> #include <queue> #include <cstring> using namespace std; typedef long long ll; struct edge{ int head; int tail; int weight; bool flag; bool operator < (const edge& p) const{ return weight<p.weight; } }; struct mstNode{ int rank; int weight; int next; }; struct node{ int rank; int max;//从某个点到它的路径中的最大边的长度 node(int r=-1,int m=-1):rank(r),max(m){} }; const int MAX=100000; int n; int m; int num; int p[MAX]; int maxWeight[301][301]; int Index[301]; mstNode mstree[602]; edge edges[MAX]; void makeSet(){ for(int i=0;i<=n;i++) p[i]=i; } int findSet(int x){ if(x!=p[x]) p[x]=findSet(p[x]); return p[x]; } //是从下向上建树的 void addEdge(int head,int tail,int weight){ mstree[num].rank=tail; mstree[num].weight=weight; mstree[num].next=Index[head]; Index[head]=num++; } inline ll kruscal(){ int i,x, y,sum=0; makeSet(); sort(edges,edges+m); for(i=0;i<m;i++){ x=findSet(edges[i].head); y=findSet(edges[i].tail); if(x!=y){ p[x]=y; addEdge(edges[i].head,edges[i].tail,edges[i].weight); addEdge(edges[i].tail,edges[i].head,edges[i].weight); edges[i].flag=true; sum+=edges[i].weight; } } return sum; } void bfs(int p){ int i; bool visited[301]; memset(visited,0,sizeof(visited)); queue<node> que; node now(p,0); node adj; que.push(now); visited[p]=true; while(!que.empty()){ node frontNode=que.front();que.pop(); for(i=Index[frontNode.rank];i!=-1;i=mstree[i].next){ adj.rank=mstree[i].rank; adj.max=mstree[i].weight; if(!visited[adj.rank]){ if(frontNode.max>adj.max) adj.max=frontNode.max; maxWeight[p][adj.rank]=adj.max; visited[adj.rank] = true; que.push(adj); } } } } ll secondaryMST(){ int i; ll sum=kruscal(); ll secSum=999999999; ll tem; for(i=1;i<=n;i++) bfs(i); for(i=0;i<m;i++) if(!edges[i].flag){ tem=sum+edges[i].weight-maxWeight[edges[i].head][edges[i].tail]; if(secSum>tem) secSum=tem; } return secSum; } int main(){ while(~scanf("%d %d",&n,&m)){ for(int i=0; i<m;i++){ scanf("%d %d %d",&edges[i].head,&edges[i].tail,&edges[i].weight); edges[i].flag=false; } num=0; memset(Index,-1,sizeof(Index)); printf("%lld\n",secondaryMST()); } }
相关文章推荐
- 这个高仿真框架AI2-THOR,想让让强化学习快速走进现实世界
- 世界就是一个班(转)
- 当今世界智商最高十大天才
- 世界首例“换头术”将在中国进行中方团队加入
- 最瘦女人震惊世界 女人何苦为难自己?
- star法则 世界500强HR强力推崇
- 世界500强面试推理题求答案
- 马云给雅虎员工作的精彩演讲:爱迪生欺骗了世界!
- 世界首富如何炼成? 看盖茨20条箴言
- 蚂蜂窝VS穷游最世界-自由行类App分析
- 偶感——自我世界 现实 世俗
- 现实世界的Windows Azure: 在选举高峰期塞尔维亚国家通讯社网站成功地服务于访客
- 【DFS】HDU2181哈密顿绕行世界问题
- Google,用技术改变世界?
- 女高级工程师相信世界末日 捐掉几百万家产
- HDU 2181 哈密顿绕行世界问题(DFS 深度优先搜素)
- 影响算法世界的十位大师
- 游戏开发世界的Lua语言
- LoaderManager使用详解(一)---没有Loader之前的世界
- 世界十大豪华游艇