HDU 6041.I Curse Myself 无向仙人掌图
Posted GeekZRF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6041.I Curse Myself 无向仙人掌图相关的知识,希望对你有一定的参考价值。
I Curse Myself
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2266 Accepted Submission(s): 544
Problem Description
There is a connected undirected graph with weights on its edges. It is guaranteed that each edge appears in at most one simple cycle.
Assuming that the weight of a weighted spanning tree is the sum of weights on its edges, define V(k) as the weight of the k-th smallest weighted spanning tree of this graph, however, V(k) would be defined as zero if there did not exist k different weighted spanning trees.
Please calculate (∑k=1Kk⋅V(k))mod232.
Assuming that the weight of a weighted spanning tree is the sum of weights on its edges, define V(k) as the weight of the k-th smallest weighted spanning tree of this graph, however, V(k) would be defined as zero if there did not exist k different weighted spanning trees.
Please calculate (∑k=1Kk⋅V(k))mod232.
Input
The input contains multiple test cases.
For each test case, the first line contains two positive integers n,m (2≤n≤1000,n−1≤m≤2n−3), the number of nodes and the number of edges of this graph.
Each of the next m lines contains three positive integers x,y,z (1≤x,y≤n,1≤z≤106), meaning an edge weighted z between node x and node y. There does not exist multi-edge or self-loop in this graph.
The last line contains a positive integer K (1≤K≤105).
For each test case, the first line contains two positive integers n,m (2≤n≤1000,n−1≤m≤2n−3), the number of nodes and the number of edges of this graph.
Each of the next m lines contains three positive integers x,y,z (1≤x,y≤n,1≤z≤106), meaning an edge weighted z between node x and node y. There does not exist multi-edge or self-loop in this graph.
The last line contains a positive integer K (1≤K≤105).
Output
For each test case, output "Case #x: y" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
Sample Input
4 3
1 2 1
1 3 2
1 4 3
1
3 3
1 2 1
2 3 2
3 1 3
4
6 7
1 2 4
1 3 2
3 5 7
1 5 3
2 4 1
2 6 2
6 4 5
7
Sample Output
Case #1: 6
Case #2:26
Case #3: 493
Source
Recommend
题意:有一个n个结点,m条无向边的仙人掌图。求删除一些边形成生成树,求前k小生成树。
思路:因为是一个仙人掌图,所以每条边最多在一个简单环内。所以只需要删除每个简单环内的一条边就能形成生成树。
代码:
无向仙人掌图
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #include<stack> #include<vector> #include<map> #include<set> #include<bitset> using namespace std; #define PI acos(-1.0) #define eps 1e-8 typedef long long ll; typedef pair<int,int> P; const int N=1e3+100,M=4e3+100; struct edge { int from,to; int w; int next; }; int n,m,k; edge es[M]; int cnt,head[N]; int dfs_clock=0; int pre[N],low[N]; stack<int>s; void init(int n) { cnt=0; dfs_clock=0; for(int i=0; i<=n+10; i++) head[i]=-1,pre[i]=0; } void addedge(int u,int v,int w) { cnt++; es[cnt].from=u,es[cnt].to=v; es[cnt].w=w; es[cnt].next=head[u]; head[u]=cnt; } int tmp[100100],ans[100100]; struct node { int num; int id; bool operator <(const node x) const { return x.num>num; } }; void unit(priority_queue<node> &q) { tmp[0]=0; while(tmp[0]<k&&!q.empty()) { node x=q.top(); q.pop(); tmp[++tmp[0]]=x.num; if(++x.id<=ans[0]) q.push((node) { x.num-ans[x.id-1]+ans[x.id],x.id }); } ans[0]=0; for(int i=1; i<=tmp[0]; i++) ans[++ans[0]]=tmp[i]; } bool dfs(int u,int fa) { pre[u]=low[u]=++dfs_clock; for(int i=head[u]; i!=-1; i=es[i].next) { int v=es[i].to; if(v==fa) continue; if(!pre[v]) { s.push(i); dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=pre[u]) { priority_queue<node>q; while(!s.empty()) { int poi=s.top(); s.pop(); q.push((node){ans[1]+es[poi].w,1}); if(poi==i) break; } if(q.size()>1) unit(q); } } else if(pre[v]<pre[u]&&v!=fa) { s.push(i); low[u]=min(low[u],pre[v]); } } } int main() { int Case=0; while(scanf("%d%d",&n,&m)!=EOF) { init(n); int all=0; for(int i=1; i<=m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); all+=w; addedge(u,v,w),addedge(v,u,w); } scanf("%d",&k); ans[0]=0,ans[++ans[0]]=0; dfs(1,0); ll sum=0,mod=(1LL<<32); for(int i=1; i<=ans[0]; i++) sum=(sum+(1LL*(all-ans[i])*i)%mod)%mod; printf("Case #%d: %lld\n",++Case,sum); } return 0; }
以上是关于HDU 6041.I Curse Myself 无向仙人掌图的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6041.I Curse Myself 无向仙人掌图
6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场