【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 }
AC代码(Kruskal)

 

时隔一月,重新又做。。。

重新写一下对于为什么是求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 }
AC代码(Prim)

 

posted @ 2018-10-01 20:22  Mr^Kevin  阅读(230)  评论(0编辑  收藏  举报