CSU 1541 There is No Alternative【最小生成树+思维】
2016-04-23 20:32
676 查看
1541: There is No Alternative
Time Limit: 3 Sec Memory Limit: 256 MBSubmit: 274 Solved: 74
[Submit][Status][Web
Board]
Description
Input
Output
Sample Input
4 4 1 2 3 1 3 3 2 3 3 2 4 3
Sample Output
1 3
HINT
Source
题目大意:给你n个点,m条边,求连接所有岛屿的权值和最小的边里边,哪些是必须建立的。分析:其实就是在最小生成树中找到哪些边是必须建立的,并且求一下这些边的权值和。
思路:
对于这样一种情况:
对于这个图的最小生成树的值很好看出权值和为4.对于这三条边,也很容易分析出没有哪一条边是在最小生成树里边必须建立的。但是如果是这样的情况:
不难看出有两条边是必须建立的,分别是:a-c,b-c,那么我们到底要怎样判断一条边是否一定在最小生成树里边呢?
首先对于m条边排序,使用克鲁斯卡尔算法将每一条贪心入树的边都标记上,然后再对于这些个标记的边挨个枚举,如果去掉这个当前枚举到的边再求一下最小生成树的权值,如果权值等于第一次求的最小生成树的权值,辣么说明,这条边,在最小生成树里边,有,和没有,都是一样的,因为这个时候有其他边能够替代这条边形成一颗最小生成树(毕竟一个图里边最小生成树不一定是唯一的)。
辣么如果不等呢?那就说明这条边如果不建立的话,形成的图,无论能否形成一颗树(n-1条边),无论能否连通,如果权值不等于最小生成树的值,辣么说明这条边呢,没有了的话是形成不了正确的一颗最小生成树的。所以,这种情况,就是我们需要找的情况。
对于刚刚语言描述的代码实现:
sort(a,a+m,cmp);//排序 for(int i=0;i<m;i++)//求一下最小生成树的值 { if(find(a[i].x)!=find(a[i].y)) { merge(a[i].x,a[i].y); mst+=a[i].w; a[i].falg=1;//如果这条边能贪心入树,标记上,一会要枚举 } } //printf("%d\n",mst); int cont=0;//必须建立的边的条数 int sum=0;//权值和 for(int i=0;i<m;i++) { //printf("%d\n",a[i].falg); if(a[i].falg==1)//枚举每一条在我们找到的最小生成树里边的边 { init();//f【i】=i int tmp=0; for(int j=0;j<m;j++) { if(i==j)continue;//去掉这条边 if(find(a[j].x)!=find(a[j].y))//求这个时候的最小生成树 { merge(a[j].x,a[j].y); tmp+=a[j].w; } } //printf("%d\n",tmp); if(tmp!=mst){cont++;sum+=a[i].w;}//如果权值和最小生成树的权值不等,辣么说明这条边,是一定需要建立的。 } }
最后是完整的AC代码:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct zuobiao { int x,y,w,falg; }a[1000000]; int mst; int f[100000]; int find(int a) { int r=a; while(f[r]!=r) r=f[r]; int i=a; int j; while(i!=r) { j=f[i]; f[i]=r; i=j; } return r; } void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) f[B]=A; } int n,m; int cmp(zuobiao a,zuobiao b) { return a.w<b.w; } void init() { for(int i=0;i<=n;i++) { f[i]=i; } } int main() { scanf("%d%d",&n,&m); init(); for(int i=0;i<m;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w); a[i].falg=0; } sort(a,a+m,cmp); for(int i=0;i<m;i++) { if(find(a[i].x)!=find(a[i].y)) { merge(a[i].x,a[i].y); mst+=a[i].w; a[i].falg=1; } } //printf("%d\n",mst); int cont=0; int sum=0; for(int i=0;i<m;i++) { //printf("%d\n",a[i].falg); if(a[i].falg==1) { init(); int tmp=0; for(int j=0;j<m;j++) { if(i==j)continue; if(find(a[j].x)!=find(a[j].y)) { merge(a[j].x,a[j].y); tmp+=a[j].w; } } //printf("%d\n",tmp); if(tmp!=mst){cont++;sum+=a[i].w;} } } printf("%d %d\n",cont,sum); return 0; }
相关文章推荐
- CSU 1202 剪刀石头布(水题)
- csu 1716: Morse string暴力过
- CSU 1458 : Booking
- CSU 1506 - Double Shortest Paths(网络流’最小费用流)
- CSU 1527 - Bounty Hunter(DP‘双调旅行商问题)
- CSU 1529 - Equator(双端队列)
- CSU 1598 最长公共前缀 KMP连续匹配
- CSU 1596 Dick.Z 的炉石赛 数学期望
- CSU 1600: Twenty-four point
- CSU 1601: War
- CSU 1603: Scheduling the final examination
- CSU 1604: SunnyPig
- CSU 1607: Do You Have The Template?
- CSU 1654: 收集金币
- CSU 1648: Swipe
- CSU 1646: HearthStone
- CSU 1660: K-Cycle
- 第一场
- 第二场
- 第三次