百度之星 初赛第二轮题解

 第一轮因为没有时间就没做了。据说较第二轮难一些。

第二轮题目确实比较水。

A题 高斯消元,具体思路还不完全会。待之后补充。

B题 二分答案+并查集。

C题 简单dp

D题 暴力枚举即可。

简单分析及代码:

B:题目大意是给N(N<=1000)个网页,分成k个聚类,要求类与类之间的网页的差异值至少都为t,求最大的t,每个类至少要有一个网页,差异值计算类似于几何距离。

算法:

  • 计算任意两个网页的差异值,即为diff[i][j],其中最大值记为maxd,最小值mind。
  • 二分答案,区间[mind,maxd],每次累加一个precision = 1e-9.
  • 判断某个t值是否可以分成k个聚类,经过分析对于任意一个网页i,计有m个diff[i][j] < t ,则i与这m个需要放在一个类中,显然,这就成了合并树的问题。并查集很轻松就搞定了。

附代码如下:

  
  
  
  
  1. #include <stdio.h> 
  2.  
  3. #include <iostream> 
  4.  
  5. #include <string.h> 
  6.  
  7. #include <set> 
  8.  
  9.   
  10.  
  11. using namespace std; 
  12.  
  13.   
  14.  
  15. const int maxn = 1024 ; 
  16.  
  17. int n , k , father[maxn] ; 
  18.  
  19. double diff[maxn][maxn] , x[maxn] , y[maxn] , z[maxn] , mind , maxd ; 
  20.  
  21. bool vis[maxn] ; 
  22.  
  23. const double precision = 1e-9 ; 
  24.  
  25.   
  26.  
  27. inline double get_max(double mm,double nn) {    return mm > nn ? mm : nn ;  } 
  28.  
  29. inline double get_min(double mm,double nn) {    return mm < nn ? mm : nn ;  } 
  30.  
  31.   
  32.  
  33. void myUnion(int i,int j) 
  34.  
  35.  
  36.     father[i] = j ; 
  37.  
  38.  
  39.   
  40.  
  41. int find_anc(int i) {   return father[i] == i ? i : ( father[i] = find_anc(father[i]) ) ;   } 
  42.  
  43.   
  44.  
  45. bool check(double pos) 
  46.  
  47.  
  48.     int i , j , cnt ; 
  49.  
  50.     cnt = 1 ; 
  51.  
  52.     memset(vis,0,sizeof(vis)); 
  53.  
  54.     for( i = 1 ; i <= n ; i++) father[i] = i ; 
  55.  
  56.     for ( i = 1 ; i <= n ; i++) 
  57.  
  58.     { 
  59.  
  60.         for( j = 1 ; j <= n ; j++) if( i != j ) 
  61.  
  62.         { 
  63.  
  64.             if( diff[i][j] < pos ) myUnion(find_anc(i),find_anc(j)); 
  65.  
  66.         } 
  67.  
  68.     } 
  69.  
  70.     int sth = 0 ; 
  71.  
  72.     for( i = 1 ; i <= n ; i++) if(!vis[j=find_anc(i)]) {    sth++;  vis[j] = 1 ;    } 
  73.  
  74.     return sth >= k ; 
  75.  
  76.  
  77.   
  78.  
  79. void solve() 
  80.  
  81.  
  82.     int i , j  ; 
  83.  
  84.     double l , r , mid ; 
  85.  
  86.     l = mind ; r = maxd ; 
  87.  
  88.     while ( l <= r ) 
  89.  
  90.     { 
  91.  
  92.         mid = ( l+r ) / 2.0 ; 
  93.  
  94.         //判断mid是否可以构成K个类.. 
  95.  
  96.         if (check(mid)) l = mid+precision ; 
  97.  
  98.         else r = mid - precision ; 
  99.  
  100.     } 
  101.  
  102.     printf("%.6lf\n",r); 
  103.  
  104.  
  105.   
  106.  
  107. int main() 
  108.  
  109.  
  110.     int i , j  ; 
  111.  
  112.     while (~scanf("%d%d",&n,&k)) 
  113.  
  114.     { 
  115.  
  116.         for ( i = 1 ; i <= n ; i++) scanf("%lf%lf%lf",&x[i],&y[i],&z[i]); 
  117.  
  118.         maxd = -1.0 ; mind = 2.0 ; 
  119.  
  120.         for( i = 1 ; i <= n ; i++) 
  121.  
  122.             for( j = i ; j <= n ; j++) 
  123.  
  124.             { 
  125.  
  126.                 diff[j][i] = diff[i][j] = (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]); 
  127.  
  128.                 mind = get_min(mind,diff[i][j]); 
  129.  
  130.                 maxd = get_max(maxd,diff[i][j]); 
  131.  
  132.             } 
  133.  
  134.         solve(); 
  135.  
  136.     } 
  137.  

C题大意:有2种礼物,每个礼物有值a,b和数量k,有n(n<=1000)个人,每个人要有一个礼物且每个人也有值x,y,每个人获得礼物的满意度为a*x+b*y,求最大的满意度。

显然是个dp问题,状态方程为:

dp[i][j]表示前i个人用了j个第一种礼物。

dp[i][j] = max(dp[i-1][j-1]+第一种礼物,dp[i-1][j]+第二种礼物).

注意边界及初始条件即可。

通过分析可以发现一些单调条件,可以优化一些,附代码如下:

  
  
  
  
  1. #include <stdio.h> 
  2.  
  3. #include <iostream> 
  4.  
  5. #include <string.h> 
  6.  
  7. #include <set> 
  8.  
  9.   
  10.  
  11. using namespace std; 
  12.  
  13.   
  14.  
  15. const int maxn = 1024 ; 
  16.  
  17. int n , x[maxn] , y[maxn] , a , aa , b , bb , k , kk , dp[maxn][maxn] , one[maxn] , two[maxn] ; 
  18.  
  19.   
  20.  
  21. inline int get_max(int mm,int nn) { return mm > nn ? mm : nn ;  } 
  22.  
  23.   
  24.  
  25. void solve() 
  26.  
  27.  
  28.     int i , j , ans ; 
  29.  
  30.     for ( i = 0 ; i <= k ; i++) dp[0][k] = 0 ; 
  31.  
  32.     for( i = 1 ; i <= n ; i++) { one[i] = x[i]*a+y[i]*b;    two[i] = x[i]*aa+y[i]*bb;   } 
  33.  
  34.     for( i = 1 ; i <= n ; i++) 
  35.  
  36.     { 
  37.  
  38.         if( i <= kk ) 
  39.  
  40.             dp[i][0] = dp[i-1][0] + two[i] ; 
  41.  
  42.         else 
  43.  
  44.             dp[i][0] = -1 ; 
  45.  
  46.         for( j = 1 ; j <= k ; j++) 
  47.  
  48.         { 
  49.  
  50.             dp[i][j] = dp[i-1][j-1] + one[i] ; 
  51.  
  52.             if( (i-j) <= kk ) dp[i][j] = get_max(dp[i][j],dp[i-1][j]+two[i]); 
  53.  
  54.         } 
  55.  
  56.     } 
  57.  
  58.     for( ans = i = 0 ; i <= k ; i++) ans = get_max(ans,dp[n][i]) ; 
  59.  
  60.     printf("%d\n",ans); 
  61.  
  62.  
  63.   
  64.  
  65. int main() 
  66.  
  67.  
  68.     int i ; 
  69.  
  70.     while (~scanf("%d",&n)) 
  71.  
  72.     { 
  73.  
  74.         for ( i = 1 ; i <= n ; i++) scanf("%d%d",&x[i],&y[i]); 
  75.  
  76.         scanf("%d%d%d",&k,&a,&b); 
  77.  
  78.         scanf("%d%d%d",&kk,&aa,&bb); 
  79.  
  80.         solve(); 
  81.  
  82.     } 
  83.  

d题大意:有n(n<=50)个靶子,每个靶子沿着一定的轨迹进行移动,移动时间为10s,求最多能同时射中几个靶子。射击时间貌似不一定是整数,看来代码可能有问题= =

假定是整数时刻射击,则枚举每秒钟每个靶子的位置,然后计算最多有几个靶子在同一直线上即可,这里暴力处理。

代码如下: 

  
  
  
  
  1. #include <stdio.h> 
  2.  
  3. #include <iostream> 
  4.  
  5. #include <string.h> 
  6.  
  7. #include <set> 
  8.  
  9.   
  10.  
  11. using namespace std; 
  12.  
  13.   
  14.  
  15. const int maxn = 50 ; 
  16.  
  17. int n , x[maxn] , y[maxn] , a[maxn] , b[maxn] ; 
  18.  
  19. double increa[maxn] ,increb[maxn] , xx[maxn] , yy[maxn] ; 
  20.  
  21. bool vis[maxn][maxn] ; 
  22.  
  23.   
  24.  
  25. inline int get_max(int mm,int nn) { return mm > nn ? mm : nn ;  } 
  26.  
  27.   
  28.  
  29. int dosth() 
  30.  
  31.  
  32.     memset(vis,0,sizeof(vis)); 
  33.  
  34.     set<int> st; 
  35.  
  36.     int i , j , k , ans ; 
  37.  
  38.     for ( i = 0 , ans = 1 ; i < n ; i++) 
  39.  
  40.     { 
  41.  
  42.         for ( j = 0 ; j < n ; j++) 
  43.  
  44.         { 
  45.  
  46.             if( i != j && !vis[i][j] ) 
  47.  
  48.             { 
  49.  
  50.                 st.clear(); 
  51.  
  52.                 st.insert(i); 
  53.  
  54.                 st.insert(j); 
  55.  
  56.                 for ( k = 0 ; k < n ; k++) if( k != i && k != j ) 
  57.  
  58.                 { 
  59.  
  60.                     if( ( yy[j] - yy[i] ) * ( xx[k] - xx[j] ) == ( yy[k] - yy[j] ) * ( xx[j] - xx[i] ) )  
  61.  
  62.                     { 
  63.  
  64.                         st.insert(k); 
  65.  
  66.                     } 
  67.  
  68.                 } 
  69.  
  70.                 ans = get_max(ans,st.size()); 
  71.  
  72.                 set<int>::iterator ite1,ite2 ; 
  73.  
  74.                 for ( ite1 = st.begin() ; ite1 != st.end() ; ite1++) 
  75.  
  76.                 { 
  77.  
  78.                     ite2 = ite1 ; 
  79.  
  80.                     ite2++; 
  81.  
  82.                     for ( ; ite2 != st.end() ; ite2++) 
  83.  
  84.                     { 
  85.  
  86.                         if( *ite1 != *ite2 ) 
  87.  
  88.                         { 
  89.  
  90.                             vis[*ite1][*ite2] = vis[*ite2][*ite1] = 1 ; 
  91.  
  92.                         } 
  93.  
  94.                     } 
  95.  
  96.                 } 
  97.  
  98.             } 
  99.  
  100.         } 
  101.  
  102.     } 
  103.  
  104.     return ans ; 
  105.  
  106.  
  107.   
  108.  
  109. void solve() 
  110.  
  111.  
  112.     int i , j , ans ; 
  113.  
  114.     for( i = 0 ; i < n ; i++) { increa[i] = 0.1 * a[i] ;    increb[i] = 0.1 * b[i] ;    } 
  115.  
  116.     for ( i = 0 , ans = 1 ; i <= 10 ; i++) 
  117.  
  118.     { 
  119.  
  120.         for( j = 0 ; j < n ; j++) { xx[j] = increa[j] * i + x[j] ;  yy[j] = increb[j] * i + y[j] ;  } 
  121.  
  122.         ans = get_max(ans,dosth()); 
  123.  
  124.     } 
  125.  
  126.     printf("%d\n",ans); 
  127.  
  128.  
  129.   
  130.  
  131. int main() 
  132.  
  133.  
  134.     int i ; 
  135.  
  136.     while (~scanf("%d",&n)) 
  137.  
  138.     { 
  139.  
  140.         for( i = 0 ; i < n ; i++) scanf("%d%d%d%d",&x[i],&y[i],&a[i],&b[i]); 
  141.  
  142.         solve(); 
  143.  
  144.     } 
  145.  

水平有限,不能保证分析和代码都正确。

 

 

 

你可能感兴趣的:(百度之星)