NOIP2014联合权值

无向连通图G有n个点,n-1条边。点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1。图上两点(u, v)的距离定义为u点到v点的最短距离。对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值。

请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

题目链接:codevs http://www.cnblogs.com/smileandyxu/p/5348411.html

图论问题,70分暴力都很好打吧,只要枚举所有点dfs找到他的距离为二的点,维护一个tot和一个max就可以了,细节自己想想,代码

等下会贴出来,正解是乘法的结合律,这个题目可以转换一下,对于每个点对,可以看成由一点中间点中转而成,就是每个点对中必定有

且只隔一个点吧,因为图是棵树,只要枚举每个入度为1的点作为中转点,然后将其儿子与其他所有儿子相乘就可以了,但这是n平方的啊!会超时。

所以我们用乘法原理,统计所有儿子权值和,然后用权值和剪去自己的权值的值再乘自己的权值,这样就是O(n)完成了。

另外,推荐我的博客:http://www.cnblogs.com/renjianshige/

暴力代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<cstring> 
const int MAXN=200010;
using namespace std;
struct edge{
    int first;
    int next;
    int to;
    int quan;
}a[2*MAXN];
bool b[MAXN];
struct node{
    int now;
    int fa;
    node(){}
    node(int _now,int _fa):now(_now),fa(_fa){}
};
int dian[MAXN];
int in[MAXN];
int n,num=0;
void addedge(int from,int to){
    a[++num].to=to;
    a[num].quan=1;
    a[num].next=a[from].first;
    a[from].first=num;
}
long long tott=0,big=0;
void dfs(int now,int fa,int time){
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==fa) continue;
        if(time==2){
            if(b[to]) continue;
            long long dianquan=dian[fa]*dian[to];
            big=max(big,dianquan);
            tott=(tott+dianquan)%10007;
            continue; 
        }
        dfs(to,now,time+1);
    }
}
int main(){
    memset(dian,0,sizeof(dian));
    memset(b,0,sizeof(b));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&dian[i]);
    }
    for(int i=1;i<=n;i++){
        dfs(i,0,1);
        b[i]=1;
    }
    printf("%lld %lld
",big,(tott*2)%10007);
    return 0;
}

AC代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<cstring>
const int MAXN=200010;
using namespace std;
struct edge{
    int first;
    int next;
    int to;
    int quan;
}a[2*MAXN];
bool b[MAXN];
int dian[MAXN];
int in[MAXN];
int n,num=0;
void addedge(int from,int to){
    a[++num].to=to;
    a[num].quan=1;
    a[num].next=a[from].first;
    a[from].first=num;
}
long long tott=0,big=0;
void dfs(int now){
  long long tot=0,big1=0,big2=0;
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        tot=(tot+dian[to])%10007;
        if(dian[to]>big1)
          {
            big1=dian[to];
            continue;
          }
        if(dian[to]<=big1&&dian[to]>big2) big2=dian[to];
    }
    for(int i=a[now].first;i;i=a[i].next){
      tott+=dian[a[i].to]*(tot-dian[a[i].to])%10007;
      if(tott<0) tott+=10007;
      tott=tott%10007;
    }
    if(big<big1*big2) big=big1*big2;
}
int main(){
    memset(dian,0,sizeof(dian));
    memset(b,0,sizeof(b));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
        in[x]++;
        in[y]++;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&dian[i]);
    }
    for(int i=1;i<=n;i++){
      if(in[i]==1) continue;
      dfs(i);
    }
    printf("%lld %lld
",big,tott%10007);
    return 0;
}
原文地址:https://www.cnblogs.com/renjianshige/p/6995582.html