1. 程式人生 > >2017多校第一場 HDU 6041 I Curse Myself Tarjan找環+K路歸併

2017多校第一場 HDU 6041 I Curse Myself Tarjan找環+K路歸併

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.

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).

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

解法:

這裡寫圖片描述

Tarjan找環,然後執行K路歸併,這個模型在白書的190頁上有例題。下面提到的暴力O(MK)的並不會。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+7;
const int maxm = 1e5+5;
struct edge{
    int v,w,next;
}E[maxn*4];
int n,m,k,head[maxn],arr[maxm],ans[maxm],tmp[maxm],dfn[maxn],dfsclk,edgecnt;
void init(){
    dfsclk=edgecnt=0;
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    ans[0]=1;
    ans[1]=0;
}
void add(int u, int v, int w){
    E[edgecnt].v=v,E[edgecnt].w=w,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
struct node{
    int val,u,v;
    node(){}
    node(int val,int u,int v):val(val),u(u),v(v){}
    bool operator < (const node&rhs) const{
        return val<rhs.val;
    }
};
void merge(int *A, int *B)
{
    priority_queue<node>q;
    sort(B+1, B+B[0]+1);
    for(int i=1; i<=B[0]; i++) q.push(node(A[1]+B[i],1,i));
    tmp[0]=0;
    while(tmp[0]<k&&!q.empty()){
        node x = q.top(); q.pop();
        tmp[++tmp[0]] = x.val;
        if(x.u<A[0]){
            q.push(node(A[x.u+1]+B[x.v],x.u+1,x.v));
        }
    }
    for(int i=0; i<=tmp[0]; i++) A[i]=tmp[i];
}
stack <int> st;
int tarjan(int u, int fa){
    int lowu=dfn[u]=++dfsclk;
    for(int i=head[u]; ~i; i=E[i].next){
        int v=E[i].v;
        if(!dfn[v]){
            st.push(i);
            int lowv = tarjan(v, u);
            lowu = min(lowu, lowv);
            if(lowv>=dfn[u]){
                arr[0]=0;
                while(1)
                {
                    int id=st.top(); st.pop();
                    arr[++arr[0]]=E[id].w;
                    if(id == i) break;
                }
                if(arr[0]>1) merge(ans, arr);
            }
        }
        else if(dfn[v]<dfn[u]&&v!=fa){
            st.push(i);
            lowu=min(lowu,dfn[v]);
        }
    }
    return lowu;
}
void find_bcc(int n)
{
    for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i,-1);
}
int main()
{
    int ks=0;
    while(~scanf("%d %d", &n,&m))
    {
        init();
        int sum=0;
        for(int i=1; i<=m; i++){
            int u,v,w;
            scanf("%d %d %d", &u,&v,&w);
            add(u,v,w);
            add(v,u,w);
            sum+=w;
        }
        scanf("%d",&k);
        find_bcc(n);
        unsigned res=0;
        for(int i=1; i<=ans[0]; i++){
            res += (unsigned)(sum-ans[i])*i;
        }
        printf("Case #%d: %u\n", ++ks, res);
    }
    return 0;
}