买礼物
原题链接:https://www.luogu.org/problem/show?pid=1194#sub
日常数组开小(1/1)。
一个裸的最小生成树。跑一遍最小生成树记录一下所花价钱,然后扫一下father数组把没优惠的补上,输出就好了。
参考代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #define maxn 500000 6 using namespace std; 7 struct Edge{ 8 int from,to,dis; 9 bool operator<(const Edge &rhs)const{ 10 return dis < rhs.dis; 11 } 12 }; 13 inline int read(){ 14 int num = 0; 15 char c; 16 bool flag = false; 17 while ((c = getchar()) == ' ' || c == '\n' || c == '\r'); 18 if (c == '-') 19 flag = true; 20 else 21 num = c - '0'; 22 while (isdigit(c = getchar())) 23 num = num * 10 + c - '0'; 24 return (flag ? -1 : 1) * num; 25 } 26 Edge edge[maxn]; 27 int father[maxn]; 28 int n,m; 29 int tot = 0; 30 int ans,totedge,readnum; 31 int find(int x){ 32 if (father[x] == x) 33 return father[x]; 34 else 35 return find(father[x]); 36 } 37 void merge(int x,int y){ 38 father[find(y)] = find(x); 39 } 40 bool check(int x,int y){ 41 return find(x) == find(y); 42 } 43 int main(){ 44 n = read();m = read(); 45 for (register int i=1;i<=m;i++) 46 father[i] = i; 47 for (register int i=1;i<=m;i++) 48 for (register int j=1;j<=m;j++){ 49 readnum = read(); 50 if (readnum!=0){ 51 edge[++tot].from = i; 52 edge[tot].to = j; 53 edge[tot].dis = readnum; 54 } 55 } 56 sort(edge+1,edge+tot+1); 57 for (register int i=1;i<=tot;i++){ 58 int u = edge[i].from; 59 int v = edge[i].to; 60 if (!check(u,v)){ 61 totedge++; 62 ans += edge[i].dis; 63 merge(u,v); 64 if (totedge == m-1) 65 break; 66 } 67 } 68 for (register int i=1;i<=n;i++) 69 if (father[i] == i) 70 ans += n; 71 printf("%d\n",ans); 72 return 0; 73 }
一切无法杀死我的,都将使我变得更加强大。