百度之星 初賽第二輪題解

 第一輪因爲沒有時間就沒做了。據說較第二輪難一些。

第二輪題目確實比較水。

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.  

水平有限,不能保證分析和代碼都正確。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章