码迷,mamicode.com
首页 > 其他好文 > 详细

[題解/考試]國王飲水記

时间:2019-03-07 00:42:57      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:while   并查集   algo   不可   reg   space   sum   更新   nbsp   

前言:今日又考試了,一道斐波那契的入門題因為沒有特判0錯了一個點,兩道不會,結果連rk7、8都沒拿到,

前天把鉛筆盒丟掉了,裡面有筆,耳機和U盤。U盤裡有做過的題,一些模板,寒假講的東西和課件,6個遊戲,一些安裝包和一些網址。

發現丟掉以後就變得特別絕望,極度悲傷,可是這就是命運啊,你不接受那就去死好了。

人活著本來就沒有什麼意義可言,尋找意義自然也是不可能尋找到的了。

意義什麼的都是小孩子的事情,所以只能這樣活著了。

與其如此那還不如把U盤裡的東西裝到腦子裡,也不必擔心什麼了。


 

n個點,按順序有m條邊,每次詢問最大的最小生成森林的邊權和以及1號所在的聯通塊點數(包括自己)。

輸入:第一行n,m。 接下來m行,每條邊的u,v,w。

輸出:m行,每行 權值之和、1所在聯通塊的點數。

數據規模:60% n,m<=1000

     100%n,m<=5000,1<=u,v<=n,u!=v,0<w<=10^5.

對於圖G=(V,E),選取E‘ 屬於E,不產生重邊和環,并使|E‘|最大,在這個前提下,使得總邊權最小,那麼G‘=(V,E‘)就是最大的最小生成森林。


 

要想拿到100分還不知道怎麼寫,不過對我來說60分的解法都不會......

60%思路:

每讀進來一條邊就可以用并查集亂搞,如果這兩點沒有聯通,那麼直接連上就行,sum加一下w就行

如果已經聯通,那麼這條邊就有可能更新sum值,這裡可以每次都跑一次最小生成樹,重置sum再把選中的邊加上,但是複雜度有點高。

dalao的代碼:(我的還沒改出來)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define R register int 
using namespace std;
struct edge {
    int u,v,w;
    bool operator < (const edge& y)const{return w<y.w;}
}e[5001],tmp[5001];
int n,m,f[5001],s[5001],cnt=1,ans,cntw,lst;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch==-?-1:fix;
    do ret=(ret<<1)+(ret<<3)+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
inline void init(int k) {
    for(R i=1;i<=k;i++) f[i]=i,s[i]=1;
}
int getf(int x) {
    return x==f[x]?x:f[x]=getf(f[x]);
}
inline bool merge(int u,int v) {
    R uf=getf(u),vf=getf(v); if(uf==vf) return true;
    else {
        if(uf==1) {
            f[vf]=uf; s[uf]+=s[vf];
        }
        else if(vf==1) {
            f[uf]=vf; s[vf]+=s[uf];
        }
        else {
            f[vf]=uf; s[uf]+=s[vf];
        }return false;}
}
//    inline void kruskal(int k){
//        for(R i=lst+1;i<=k;i++) tmp[i].u=e[i].u,tmp[i].v=e[i].v,tmp[i].w=e[i].w; ans=0;
//        sort(tmp+1,tmp+k+1); init(k);
//        for(R i=1;i<=k;i++){
//            if(!merge(tmp[i].u,tmp[i].v)) ans+=tmp[i].w;
//        }
//    }
namespace krusk{
    int fa[5001];
    inline void init(int k) {for(R i=1;i<=k;i++) fa[i]=i;}
    int getf(int x) {
        return x==fa[x]?x:fa[x]=getf(fa[x]);
    }
    inline bool merge(int u,int v) {
        R uf=getf(u),vf=getf(v); if(uf==vf) return true;
        else {fa[vf]=uf; return false;}
    }
    inline void kruskal(int k){
        for(R i=lst+1;i<=k;i++) tmp[i].u=e[i].u,tmp[i].v=e[i].v,tmp[i].w=e[i].w; ans=0;
        sort(tmp+1,tmp+k+1); init(n);
        for(R i=1;i<=k;i++){
            if(!merge(tmp[i].u,tmp[i].v)) ans+=tmp[i].w;
        }
    }
}
signed main() {
    n=g(),m=g(); for(R i=1;i<=n;i++) f[i]=i,s[i]=1;
    for(R i=1;i<=m;i++) e[i].u=g(),e[i].v=g(),e[i].w=g();
    for(R i=1;i<=m;i++) {
        R u=e[i].u,v=e[i].v,w=e[i].w;
        if(merge(u,v)) {
            krusk::kruskal(i);    
            cntw=min(cntw,ans);
        }
        else {
            cntw+=w;
        }
        printf("%d %d\n",cntw,s[1]);
    }
    return 0;
}

以後可能會更新的吧

 

[題解/考試]國王飲水記

标签:while   并查集   algo   不可   reg   space   sum   更新   nbsp   

原文地址:https://www.cnblogs.com/superminivan/p/10486988.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!