• [NOIP2014提高组]联合权值


    题目:洛谷P1351、Vijos P1906、codevs3728、UOJ#16。

    题目大意:有一个无向连通图,有n个点n-1条边,每个点有一个权值$W_i$,每条边长度为1。规定两个距离为2的点i和j可以产生$W_i×W_j$的联合权值。求最大的联合权值是多少,联合权值之和是多少。

    解题思路:首先,距离为2的点只有两种情况:①点u和它父亲的父亲;②点u和它的兄弟。那么我们只需遍历全图,记录该点父亲的父亲即可。对于每个节点,求出它所有儿子和儿子之间的联合权值是多少,加起来即可。

    这样子可能会超时。那么我们可以用一个变量记录前面儿子的权值和,然后直接乘这个和即可。最后答案乘2。

    对于第一问,我们也思考以上两种情况。第①种很好考虑,第②种我们只需记录最大权值和次大权值,然后相乘就是可能的最大值了。

    于是就过了。

    C++ Code:

    #include<cstdio>
    #include<vector>
    using namespace std;
    vector<int>G[200002];
    int n,d[200002],ans=0,Max=0;
    bool b[200002]={0};
    void addedge(int from,int to){
    	G[from].push_back(to);
    	G[to].push_back(from);
    }
    void dfs(int u,int fa,int fasfa){
    	b[u]=true;
    	if(fasfa)ans=(ans+d[u]*d[fasfa]%10007)%10007;
    	int sum=0,no1=0,no2=0;
    	for(int i=0;i<G[u].size();++i)
    	if(!b[G[u][i]]){
    		if(d[G[u][i]]>no1)no2=no1,no1=d[G[u][i]];else
    		if(d[G[u][i]]>no2)no2=d[G[u][i]];
    		ans=(ans+d[G[u][i]]*sum%10007)%10007;
    		sum=(sum+d[G[u][i]])%10007;
    	}
    	if(no1*no2>Max)Max=no1*no2;
    	if(d[u]*d[fasfa]>Max)Max=d[u]*d[fasfa];
    	for(int i=0;i<G[u].size();++i)
    	if(!b[G[u][i]]){
    		b[G[u][i]]=true;
    		dfs(G[u][i],u,fa);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<n;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		addedge(x,y);
    	}
    	for(int i=1;i<=n;++i)scanf("%d",&d[i]);
    	dfs(1,0,0);
    	printf("%d %d
    ",Max,ans*2%10007);
    	return 0;
    }
    
  • 相关阅读:
    【转帖】C#索引器
    .NET Framework升级的挑战
    【我翻译的文章】CodeSmith发布代替和扩展LINQ to SQL的工具——PLINQO
    升级到VS2008后的一些疑惑
    【我翻译的文章】你还需要数据层吗?
    Db4Objects发布Db4o 7.0,支持透明激活
    迎接游戏开发新世界——Zune Game和Micro Game
    20071223成都俱乐部活动
    db4o发布7.2,出现.NET 3.5版本,支持LINQ
    微软推出SCE SDK及其示例MSDN Reader
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7506467.html
Copyright © 2020-2023  润新知