多校第一场I Curse Myself(HDU6041)
来源:互联网 发布:淘宝宝贝详情怎么做 编辑:程序博客网 时间:2024/05/16 19:18
此题是我第一次接触仙人掌图,第一次了解Tarjan算法,也是第一次了解了合并N个集合的解法,这么多第一次,当然要记录一下。
Tarjan算法的介绍已经在我的另一篇博客中做了介绍(tarjan算法详解),这里解不在多讲了。
还有仙人掌图的大概介绍一下,就是图中的每一条边都唯一属于一个简单环路,不清楚的可以自行百度。
这里我主要想讲的就是如何合并N个集合,求出在这N个集合任取一个数求和得到前K大个数,做法就是对集合两两合并,每次合并时得到的新集合只保存前K大的数,因为第K大的数之后的数和其他集合合并时不可能超过前K个数的结果,然后保证得到的这K个数是有序的,方便下次合并。
在具体实现中用到了优先队列(大根堆),假设要合并集合A,B, A是从大到小有序排列的,首先将A中第一个数(即最大的数)和要B集合的每一个数相加然后将结果扔到优先队列中,同时每一个结果要保留由A,B中那两个元素合并合成,这样优先队列的的第一个元素一定是两个集合合并能产生的最大的结果,然后每取出一个结果,因为A集合是有序的,因此将这个结果中A的元素后移以为,即用A中合并成这个结果的A中元素的后一个元素来替换,这样得到一个小于等于取出的这个结果的数,在放入优先队列中,如此得到前K大的结果即可。
#include <bits/stdc++.h>using namespace std;const int MAXN = 1010;//点数const int MAXE = 4020;//边数const long long mod = (1LL << 32);struct Edge{ int to, next, cost;}edge[MAXE];struct node{ int id1, id2, value; bool operator < (const node& ano) const { return value < ano.value; }};int head[MAXN], tot;int low[MAXN], dfn[MAXN], Stack[MAXN];int index, top;int K;int res[100005], rt[100005], tmp[100005];bool vis[MAXE];void addedge(int u, int v, int _cost){ edge[tot].to = v; edge[tot].cost = _cost; edge[tot].next = head[u]; head[u] = tot++;}void unit(int* a, int *b)//a是从大到小排序的{ tmp[0] = 0; priority_queue<node>que; for(int i = 1; i <= b[0]; ++i) que.push((node){1, i, a[1] + b[i]}); while(tmp[0] < K && !que.empty()) { node nn = que.top(); que.pop(); tmp[++tmp[0]] = nn.value; if(nn.id1 + 1 <= a[0]) { nn.id1 += 1; que.push((node){nn.id1, nn.id2, a[nn.id1] + b[nn.id2]}); } } for(int i = 0; i <= tmp[0]; ++i) a[i] = tmp[i]; return;}void Tarjan(int u, int fa){ dfn[u] = low[u] = index++; vis[u] = true; for(int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; if(!vis[v]) { Stack[top++] = i; Tarjan(v, u); low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]) { rt[0] = 0; int p = 0; do { p = Stack[--top]; rt[++rt[0]] = edge[p].cost; } while(p != i); if(rt[0] > 1) unit(res, rt); } } else if(low[u] > dfn[v]) { Stack[top++] = i; low[u] = min(low[u], dfn[v]); } } return;}int main(){ //freopen("1009.in", "r", stdin); //freopen("out.out", "w", stdout); int cas = 1; int n, m; while(scanf("%d%d", &n, &m) != EOF) { memset(head, -1, sizeof(head)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(vis, 0, sizeof(vis)); index = top = 0; int u, v, c; long long sum = 0LL; tot = 0; while(m--) { scanf("%d%d%d", &u, &v, &c); sum = sum + c; addedge(u, v, c); addedge(v, u, c); } scanf("%d", &K); res[0] = 1; res[1] = 0; Tarjan(1, -1); long long ans = 0; for(int i = 1; i <= res[0]; ++i) { //printf("%d%c", res[i], i == res[0] ? '\n' : ' '); ans = (ans + (1LL * i * (sum - res[i])) % mod) % mod; } printf("Case #%d: %lld\n", cas++, ans); } return 0;}
阅读全文
0 0
- 多校第一场I Curse Myself(HDU6041)
- HDU6041-I Curse Myself(k路归并)
- 2017多校第一场 HDU 6041 I Curse Myself Tarjan找环+K路归并
- 2017多校训练赛第一场 HDU 6041 I Curse Myself(仙人掌图生成树)
- HDU 6041 I Curse Myself
- HDU 6041 I Curse Myself
- HDU 6041 I Curse Myself(仙人掌+tanjan)
- HDU 6041 I Curse Myself (仙人掌图)
- HDU-6041 I Curse Myself(双连通分量+k路归并)
- HDU 6041 I Curse Myself(边双连通分量+优先队列)
- hdu 6041 I Curse Myself [2017 Multi-University Training Contest
- 2017多校一 1009题 hdu 6041 I Curse Myself 找环(tarjan) + K 路归并
- hdu 4608 I-number 多校第一场
- hdu 4869 Turn the pokers (2014多校联合第一场 I)
- 多校第一场
- 2017多校第一场(HDU6038)
- 多校联赛第一场
- 2013多校第一场
- Python常见的错误类型及其继承关系
- 小米手机无法调试应用解决Installation failed with message Failed to establish session.
- ASP常用服务器获取各类信息汇总
- swift ARC中的strong、weak、unowned
- PHP导出excel
- 多校第一场I Curse Myself(HDU6041)
- jmeter 集合点
- Centos6安装mysql5.5
- JQuery在光标位置插入内容
- 逆波兰表达式求值
- Ant与Maven在liunx上的安装
- 牛客网---2016---蘑菇街回文串
- java 日期计算
- matlab fminsearch 求取最小值失败的情况