
无向连通图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=;
using namespace std;
struct edge{
int first;
int next;
int to;
int quan;
}a[*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=;
void addedge(int from,int to){
a[++num].to=to;
a[num].quan=;
a[num].next=a[from].first;
a[from].first=num;
}
long long tott=,big=;
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==){
if(b[to]) continue;
long long dianquan=dian[fa]*dian[to];
big=max(big,dianquan);
tott=(tott+dianquan)%;
continue;
}
dfs(to,now,time+);
}
}
int main(){
memset(dian,,sizeof(dian));
memset(b,,sizeof(b));
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
for(int i=;i<=n;i++){
scanf("%d",&dian[i]);
}
for(int i=;i<=n;i++){
dfs(i,,);
b[i]=;
}
printf("%lld %lld\n",big,(tott*)%);
return ;
}
AC代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<cstring>
const int MAXN=;
using namespace std;
struct edge{
int first;
int next;
int to;
int quan;
}a[*MAXN];
bool b[MAXN];
int dian[MAXN];
int in[MAXN];
int n,num=;
void addedge(int from,int to){
a[++num].to=to;
a[num].quan=;
a[num].next=a[from].first;
a[from].first=num;
}
long long tott=,big=;
void dfs(int now){
long long tot=,big1=,big2=;
for(int i=a[now].first;i;i=a[i].next){
int to=a[i].to;
tot=(tot+dian[to])%;
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])%;
if(tott<) tott+=;
tott=tott%;
}
if(big<big1*big2) big=big1*big2;
}
int main(){
memset(dian,,sizeof(dian));
memset(b,,sizeof(b));
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
in[x]++;
in[y]++;
}
for(int i=;i<=n;i++){
scanf("%d",&dian[i]);
}
for(int i=;i<=n;i++){
if(in[i]==) continue;
dfs(i);
}
printf("%lld %lld\n",big,tott%);
return ;
}