【BZOJ3714】Kuglarz
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3714
qbxt大佬好多,我真的好弱。。。
额额,这道题的话,关键在于划归到MST,剩下的基本都不是事了。
如果我们把题目中的查询转换关系抽象成图,那么这应该是一张完全图。但如果我们想知道每个结点的奇偶性,找到一棵生成树即可。
为什么呢,可以设想三个结点a,b,c,如果我们通过查询[a,b]和[b+1,c]得到了[a,c]的奇偶性,就不会再通过查询[a,c]的奇偶性得到了。
而每条边(查询)是有费用的,把费用看成边权,MST可以做到费用最小。
但这个题在建图时注意,由于查询[i,i]也是有费用的,所以不要把i点建成一个点。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=2005,maxm=3e6+5; 5 int n,eid; 6 long long ans; 7 struct Edge { 8 int u,v,w; 9 Edge(int u=0,int v=0,int w=-1):u(u),v(v),w(w) {} 10 bool operator < (const Edge& rhs) const { 11 return w<rhs.w; 12 } 13 } edge[maxm]; 14 int f[maxn]; 15 int dj_find(int i) { 16 if(i==f[i]) return i; 17 return f[i]=dj_find(f[i]); 18 } 19 void dj_merge(int a,int b) { 20 a=dj_find(a);b=dj_find(b); 21 if(dj_find(a)!=dj_find(b)) f[a]=b; 22 } 23 int main() { 24 scanf("%d",&n); 25 int c; 26 for(int i=1;i<=n;++i) 27 for(int j=i;j<=n;++j) { 28 scanf("%d",&c); 29 edge[++eid]=Edge(i-1,j,c); 30 } 31 for(int i=0;i<=n;++i) f[i]=i; 32 sort(edge+1,edge+eid+1); 33 for(int i=1;i<=eid;++i) { 34 int u=edge[i].u,v=edge[i].v; 35 if(dj_find(u)!=dj_find(v)) { 36 ans+=edge[i].w; 37 dj_merge(u,v); 38 } 39 } 40 printf("%lld",ans); 41 return 0; 42 }
时隔一月,重新又做。。。
重新写一下对于为什么是求MST的理解:问题其实是确定每个杯子的奇偶性,如果知道了每个前缀的奇偶性就可以了,因为0的奇偶性是确定的,实际上知道每个杯子的奇偶性也就知道了,因此二者是等价的。[0,a],[a,b]和[0,b],如果知道了其中二者,就可以知道第三个,而题目要求花费最小,想象一下,这不就是一棵有n+1个点的树,你希望从0到其他各个结点都连通,且边的费用和最小吗?
上次用的Kruskal,明明是张完全图。。。这次好好写一下堆优化的Prim。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 6 using namespace std; 7 8 inline int get_num() { 9 int num = 0; 10 char c = getchar(); 11 while (c < '0' || c > '9') c = getchar(); 12 while (c >= '0' && c <= '9') 13 num = num * 10 + c - '0', c = getchar(); 14 return num; 15 } 16 17 const int maxn = 2005, inf = 0x3f3f3f3f; 18 19 int n, cost[maxn][maxn]; 20 long long ans; 21 22 int dist[maxn], vis[maxn]; 23 24 struct node { 25 int id, dist; 26 node(int i, int d) : id(i), dist(d) {} 27 bool operator < (const node& rhs) const { 28 return dist > rhs.dist; 29 } 30 }; 31 32 priority_queue<node> q; 33 34 inline void prim() { 35 memset(dist, inf, sizeof(dist)); 36 dist[0] = 0; 37 q.push(node(0, 0)); 38 while (!q.empty()) { 39 int u = q.top().id; 40 q.pop(); 41 if (vis[u]) continue; 42 vis[u] = 1; 43 ans += dist[u]; 44 for (int v = 1; v <= n; ++v) 45 if (!vis[v] && cost[u][v] < dist[v]) { 46 dist[v] = cost[u][v]; 47 q.push(node(v, dist[v])); 48 } 49 } 50 } 51 52 int main() { 53 n = get_num(); 54 for (int i = 1; i <= n; ++i) 55 for (int j = i; j <= n; ++j) 56 cost[i - 1][j] = cost[j][i - 1] = get_num(); 57 prim(); 58 printf("%lld", ans); 59 return 0; 60 }