HDU 6763 Total Eclipse

Total Eclipse

题目描述:

给一张无向图,每个点有一个权值,每次可以选择一个连通图的消去最小的那个值。连通的点权值减去最小值。

权值为0的点就不见了,花销为最小值。问把整个图的点权值消到0需要多少花销。

for example: 

3 2

3 2 3

1 2

2 3

1与2连结 2与3连接 权值为3 2 3 开始3个点连通 花销为2 权值变为 1 0 1,去掉2点 1和3不在连通分别花销1。

所以最后结果为4。 (2+1+1)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6763

(菜鸡的我,那场爆零了。。。太菜了)

 

思考:

这道题我当时试了很多办法,重大点出发合并到其他小点上,或者重小店出发。给其他大点减去一个权值。但是

都是不行的。因为单点出发就得辐射全图。如何保证这个全图就很困难。自闭3小时啥也没做出来。

后面看了题解幡然醒悟!!!!我当时想到了每次重全图减去割点(不行)。却没有逆向思维我们。每次加一个点判断

是否让原图形成一个新的连通图!!其思想都是判断该店对全图的影响,但是换种思考方式就立马变得可做了。

怎么做?

首先判断两个点是否连通最好的办法就是并查集找父亲。规定小点做父亲就行了。

其次对于添加的点做一个vis标记。确保目前在我的图中有这个点。

最后给权值排序重大点开始添加。小点能成为两个大点的联通点。

就这么简单,但是比赛时没想到。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int h[N],nt[N*5],to[N*5],fa[N],num,A[N],id[N];
bool vis[N];
bool cmp(int a,int b){
    return A[a]>A[b];
}
void add(int u,int v){
    nt[++num]=h[u];
    h[u]=num;
    to[num]=v;
}
int fid(int x){
    if(x == fa[x]) return x;
    else return fa[x]=fid(fa[x]); 
}
int main(){
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        num=0;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            vis[i]=h[i]=0;
            id[i]=fa[i]=i;
            scanf("%d",A+i);
        }
        sort(id+1,id+n+1,cmp);//按权值排大小 
        int a,b;
        for(int i=0;i<m;i++){
            scanf("%d %d",&a,&b);
            add(a,b);
            add(b,a);
        }
        int pos = 1;//初始一个点,一个连通图 
        ll ps = A[id[1]],ans=0;
        vis[id[1]]=1;//vis置1,表示在图内。 
        for(int i=2;i<=n;i++){
            ans+=(ps-A[id[i]])*pos;
            vis[id[i]]=1;
            pos++;//增加一个点,目前没跟新边,会增加一个独立点,也就是怎加一个图 
            for(int j=h[id[i]];j;j=nt[j]){
                int v=to[j];
                if(!vis[v]) continue;//不在图中的点不计算 
                int fx=fid(v);
                int fy=fid(id[i]);
                if(fx!=fy){//两个父亲不一样说明没添加该点时是不连通的 
                    if(fx>fy) fa[fx]=fy;
                    else fa[fy]=fx;
                    pos--;
                }
            }
            ps=A[id[i]];
        }
        printf("%lld\n",ans+ps*pos);//最后剩下的不要忘记加上 
    }
} 

这道题思考很重要,难度不大。但是思维没到那个地方。就是出不来。

猜你喜欢

转载自www.cnblogs.com/grisaia/p/13372485.html