正文

修剪花卉---一道竞赛题的解答2006-12-06 22:59:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/21342.html

分享到:

/*
  Name: 修剪花卉
  Copyright:
  Author:
  Date: 26-11-06 22:29
  Description:
修剪花卉
内存限制:32M


问题背景:

ZZ对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。
一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题。

于是当日课后,ZZ就向老师提出了这个问题:

一株奇怪的花卉,上面共连有N朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的。

每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的,
说明这朵花看着都让人恶心。

所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。

经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。

老师的任务就是:通过一系列“修剪”(也可以什么“修剪”都不进行),
使剩下的那株(那朵)花卉上所有花朵的“美丽指数”之和最大。

老师想了一会儿,给出了正解(交大的老师是很牛的~)。ZZ见问题被轻易攻破,
相当不爽,于是又拿来问你。

输入说明:

第一行一个整数N(1 ≤ N ≤ 16000)。表示原始的那株花卉上共N朵花。

第二行有N个整数,第I个整数表示第I朵花的美丽指数。

接下来N-1行每行两个整数a,b,表示存在一条连接第a朵花和第b朵花的枝条。

输出说明:

一个数,表示一系列“修剪”之后所能得到的“美丽指数”之和的最大值。保证绝对值不超过2147483647。

样例输入:

7

-1 -1 -1 1 1 1 0

1 4

2 5

3 6

4 7

5 7

6 7

样例输出:

3

数据范围:

对于60%的数据, 保证N≤1,000

对于100%的数据,保证N≤16,000


*/

/*
算法:先把所有的花进行分组,把连在一起的花合并到一组,那么问题就转化为求每一组中数据之和的最大值。
合并花的算法借鉴了连通问题。
*/

#include <iostream>

using namespace std;

const int N = 20000;

void Connected(int id[], int p, int q);
int MaxSum(const int data[], int id[]);

int main() 
{
 //////////此部分由用户输入数据测试代码/////////////////
// int data[N+1] = {0};
// cout << "enter data:" << endl;
// for (int i=1; i<=N; i++)
//     cin >> data[i];
// 
//    int id[N+1];
//    for (int i=0; i<=N; i++)
//     id[i] = i;
//   
//    fflush(stdin);
// cout << "enter blunch:" << endl; 
//    int p, q;
//    int i = 1;
//    while (i < N)
//    { 
//  cin >> p >> q;
//  Connected(id, p, q);
//  i++;
// }
///////////////////////////////////////////////
// /////////此部分由计算机产生大量随机数测试代码//////////////////
 int data[N+1] = {0};
 for (int i=1; i<=N; i++) //美丽指数分布在-10到10之间
     data[i] = rand()%21 - 10;
// 
// for (int i=1; i<=N; i++)
//  cout << data[i] << ' ';
// cout << endl;
 
    int id[N+1];
    for (int i=0; i<=N; i++)
     id[i] = i;

    int p, q;
    int i = 1;
    while (i < N)
 {
  p = rand() % N + 1;
  q = rand() % N + 1;
  if (p == q)
   continue;
//  cout << p << ' ' << q << "\t";
  Connected(id, p, q);
  i++;
 }
// ///////////////////////////////////// 

 cout << "\nmax = " << MaxSum(data, id) << endl;
 
 cout << clock() << endl;
    getchar();getchar();
 return 0;
}

void Connected(int id[], int p, int q)//把连在一起的花合并到一组
{
 if (id[p] == id[q]) //已经连通
  return;
 int t = id[p];
 for (int i=1; i<=N; i++)
 {
  if (id[i] == t) 
   id[i] = id[q]; 
 }
}

int MaxSum(const int data[], int id[])//求每一组中数据之和的最大值
{
 int buf[N] = {0};
 int max = 0;
 int sum = 0;

 for (int k,i=1; i<=N; i++) //遍历数组id, 计算并查找和最大的集合
 {
  if (id[i] == 0)
   continue;
  
  k = 1; 
  for (int j=i+1; j<=N; j++) //记录以i为根的所有元素的下标
  {
   if (id[j] != 0 && id[j] == id[i])
   {
    buf[k++] = j;
    id[j] = 0;
   }
  }
  buf[0] = i;
  id[i] = 0;
  
  sum = 0;
  for (int t=0; t<k; t++) //计算以i为根的集合的和
  {
   if (data[buf[t]] > 0)
    sum += data[buf[t]];
  }
  
  if (sum > max)
   max = sum;
 }
 
 return max;
}

阅读(3282) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册