I Curse Myself
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1790 Accepted Submission(s): 443
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
题意:给你一个仙人掌图(每条边最多属于一个环),去掉一些边变成生成树(即每个环去掉一条边),求出所有前k小的生成树
解题思路:先找出每个环中边的权值,每个环形成一个集合,这个可以用tarjan算法实现,然后从每个集合中拿出一个数合起来,求出前第k大的即可,这个可以用k路归并来解决
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <unordered_map>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
struct Edge
{
int v, nt, val, flag;
} edge[1009 << 2];
int s[1009], cnt;
int n, m, k, sum;
int dfn[1009], low[1009], dep, vis[1009];
stack<int>st;
int ans[100009], g[100009], c[100009];
struct node
{
int x, y, val;
node(int x = 0, int y = 0, int v = 0) :x(x), y(y), val(v) {}
bool operator<(const node &a)const
{
return val < a.val;
}
};
void AddEdge(int u, int v, int w)
{
edge[cnt].v = v, edge[cnt].nt = s[u], edge[cnt].flag = 1, edge[cnt].val = w, s[u] = cnt++;
edge[cnt].v = u, edge[cnt].nt = s[v], edge[cnt].flag = 1, edge[cnt].val = w, s[v] = cnt++;
}
void Merge(int a[], int b[])
{
priority_queue<node>q;
c[0] = 0;
for (int i = 1; i <= b[0]; i++)
{
node pre(1, i, a[1] + b[i]);
q.push(pre);
}
while (!q.empty() && c[0] < k)
{
node pre = q.top();
q.pop();
c[++c[0]] = pre.val;
if (pre.x + 1 <= a[0])
{
pre.val = a[++pre.x] + b[pre.y];
q.push(pre);
}
}
for (int i = 0; i <= c[0]; i++) a[i] = c[i];
}
void tarjan(int u, int pre) // 无向图,数据有回边.需要将其看做不同边.且边需要标记...
{
vis[u] = 1;
dfn[u] = low[u] = ++dep;
for (int i = s[u]; ~i; i = edge[i].nt)
{
int v = edge[i].v;
if (!edge[i].flag) continue;
edge[i].flag = edge[i ^ 1].flag = 0;
if (!vis[v])
{
st.push(i);
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (dfn[u] <= low[v])
{
int k;
g[0] = 0;
do
{
k = st.top();
st.pop();
g[++g[0]] = edge[k].val;
} while (k != i);
if(g[0]>1) Merge(ans, g);
}
}
else if (dfn[v] < dfn[u])
{
st.push(i);
low[u] = min(low[u], dfn[v]);
}
}
}
int main()
{
int cas = 0;
while (~scanf("%d%d", &n, &m))
{
memset(s, -1, sizeof s);
cnt = dep = sum = ans[1] = 0;
ans[0] = 1;
for (int i = 0; i < m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
AddEdge(u, v, w);
sum += w;
}
scanf("%d", &k);
memset(vis, 0, sizeof vis);
while (!st.empty()) st.pop();
tarjan(1, 0);
int ans1 = 0;
for (int i = 1; i <= ans[0]; i++)
ans1 += (sum - ans[i])*i;
printf("Case #%d: %u\n", ++cas, ans1);
}
return 0;
}