7 solutions
-
1
#include<stdio.h> #include<stdlib.h> /*图的最小生成树问题 任意两个城邦之间都有桥直接连接,则构成了图 现要装饰其中的一部分桥要保证从一个城邦到另 一个城邦之间可以完全只通过装饰的桥到达,那么 根据题意至少要2020座桥,并且要保证开支最少, 这就是典型的最小生成树问题,任意城邦之间的桥 上面是有权值的也就是桥的开销,我们通过排序依照权值 从小到大的顺序依次装饰桥,注意不能有回路否则就不能保证 从一个城邦到另一个城邦可以完全只通过装饰桥到达了 */ typedef struct tu{ //head和tail分别表示桥两边的结点 int head; int tail; int value;//表示权值 }Tu; Tu array[10000007]; int f[2027]; int cnt = 0; int count = 0; int comp(const void *a, const void *b){ //将void指针类型强制转化为结构体指针类型 Tu *c = (Tu *)a; Tu *d = (Tu *)b; return c->value-d->value; } //寻找每一个结点的根结点 int find(int x){ if(x == f[x])//如果某个结点的根结点就是他本身说明这个结点还没有连通 return x; else{ f[x] = find(f[x]);//递归调用找到f[x]的最终的根结点也就是祖先结点 return f[x];//返回f[x]的祖先结点 } } //主要是防止树种生成环 int merge(int x, int y){ int t1,t2; //找到两个结点的祖先结点判断是否在一个集合中也就是说是否有公共的祖先结点 t1 = find(x); t2 = find(y); //如果两个结点的祖先结点不等则可以进行连接 if(t1 != t2){ f[t2] = t1;//根据靠左原则t2的父节点设为t1 return 1; } return 0; } //求桥的权值 void add(int x,int y){ int a,b; int sum = 0;//每座桥的sum都可能不同因此一定要每次调用时都设为0 cnt++; array[cnt].head = x; array[cnt].tail = y; while(x!=0 || y!=0){ a = x%10; b = y%10; if(a != b){ sum += a+b; } x /= 10; y /= 10; } array[cnt].value = sum; return; } int main(){ int sum = 0; for(int i=1; i<=2021; i++) f[i] = i;//初始时每个结点的根结点就是结点本身 //列举所有桥之间连接的可能 for(int i=1; i<=2021; i++){ for(int j=i+1; j<=2021; j++){ add(i,j); } } qsort(array+1,cnt,sizeof(array[0]),comp); for(int i=1; i<=cnt; i++){ if(merge(array[i].head,array[i].tail)){ count++; sum += array[i].value; } if(count == 2020) break; } printf("%d\n",sum); }
Information
- ID
- 108
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 6
- Tags
- # Submissions
- 122
- Accepted
- 41
- Uploaded By