第一輪由於沒有時間就沒作了。聽說較第二輪難一些。ios
第二輪題目確實比較水。算法
A題 高斯消元,具體思路還不徹底會。待以後補充。ide
B題 二分答案+並查集。優化
C題 簡單dpspa
D題 暴力枚舉便可。ci
簡單分析及代碼:get
B:題目大意是給N(N<=1000)個網頁,分紅k個聚類,要求類與類之間的網頁的差別值至少都爲t,求最大的t,每一個類至少要有一個網頁,差別值計算相似於幾何距離。string
算法:it
附代碼以下:io
- #include <stdio.h>
- #include <iostream>
- #include <string.h>
- #include <set>
- using namespace std;
- const int maxn = 1024 ;
- int n , k , father[maxn] ;
- double diff[maxn][maxn] , x[maxn] , y[maxn] , z[maxn] , mind , maxd ;
- bool vis[maxn] ;
- const double precision = 1e-9 ;
- inline double get_max(double mm,double nn) { return mm > nn ? mm : nn ; }
- inline double get_min(double mm,double nn) { return mm < nn ? mm : nn ; }
- void myUnion(int i,int j)
- {
- father[i] = j ;
- }
- int find_anc(int i) { return father[i] == i ? i : ( father[i] = find_anc(father[i]) ) ; }
- bool check(double pos)
- {
- int i , j , cnt ;
- cnt = 1 ;
- memset(vis,0,sizeof(vis));
- for( i = 1 ; i <= n ; i++) father[i] = i ;
- for ( i = 1 ; i <= n ; i++)
- {
- for( j = 1 ; j <= n ; j++) if( i != j )
- {
- if( diff[i][j] < pos ) myUnion(find_anc(i),find_anc(j));
- }
- }
- int sth = 0 ;
- for( i = 1 ; i <= n ; i++) if(!vis[j=find_anc(i)]) { sth++; vis[j] = 1 ; }
- return sth >= k ;
- }
- void solve()
- {
- int i , j ;
- double l , r , mid ;
- l = mind ; r = maxd ;
- while ( l <= r )
- {
- mid = ( l+r ) / 2.0 ;
- //判斷mid是否能夠構成K個類..
- if (check(mid)) l = mid+precision ;
- else r = mid - precision ;
- }
- printf("%.6lf\n",r);
- }
- int main()
- {
- int i , j ;
- while (~scanf("%d%d",&n,&k))
- {
- for ( i = 1 ; i <= n ; i++) scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
- maxd = -1.0 ; mind = 2.0 ;
- for( i = 1 ; i <= n ; i++)
- for( j = i ; j <= n ; j++)
- {
- 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]);
- mind = get_min(mind,diff[i][j]);
- maxd = get_max(maxd,diff[i][j]);
- }
- solve();
- }
- }
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]+第二種禮物).
注意邊界及初始條件便可。
經過分析能夠發現一些單調條件,能夠優化一些,附代碼以下:
- #include <stdio.h>
- #include <iostream>
- #include <string.h>
- #include <set>
- using namespace std;
- const int maxn = 1024 ;
- int n , x[maxn] , y[maxn] , a , aa , b , bb , k , kk , dp[maxn][maxn] , one[maxn] , two[maxn] ;
- inline int get_max(int mm,int nn) { return mm > nn ? mm : nn ; }
- void solve()
- {
- int i , j , ans ;
- for ( i = 0 ; i <= k ; i++) dp[0][k] = 0 ;
- for( i = 1 ; i <= n ; i++) { one[i] = x[i]*a+y[i]*b; two[i] = x[i]*aa+y[i]*bb; }
- for( i = 1 ; i <= n ; i++)
- {
- if( i <= kk )
- dp[i][0] = dp[i-1][0] + two[i] ;
- else
- dp[i][0] = -1 ;
- for( j = 1 ; j <= k ; j++)
- {
- dp[i][j] = dp[i-1][j-1] + one[i] ;
- if( (i-j) <= kk ) dp[i][j] = get_max(dp[i][j],dp[i-1][j]+two[i]);
- }
- }
- for( ans = i = 0 ; i <= k ; i++) ans = get_max(ans,dp[n][i]) ;
- printf("%d\n",ans);
- }
- int main()
- {
- int i ;
- while (~scanf("%d",&n))
- {
- for ( i = 1 ; i <= n ; i++) scanf("%d%d",&x[i],&y[i]);
- scanf("%d%d%d",&k,&a,&b);
- scanf("%d%d%d",&kk,&aa,&bb);
- solve();
- }
- }
d題大意:有n(n<=50)個靶子,每一個靶子沿着必定的軌跡進行移動,移動時間爲10s,求最多能同時射中幾個靶子。射擊時間貌似不必定是整數,看來代碼可能有問題= =
假定是整數時刻射擊,則枚舉每秒鐘每一個靶子的位置,而後計算最多有幾個靶子在同一直線上便可,這裏暴力處理。
代碼以下:
- #include <stdio.h>
- #include <iostream>
- #include <string.h>
- #include <set>
- using namespace std;
- const int maxn = 50 ;
- int n , x[maxn] , y[maxn] , a[maxn] , b[maxn] ;
- double increa[maxn] ,increb[maxn] , xx[maxn] , yy[maxn] ;
- bool vis[maxn][maxn] ;
- inline int get_max(int mm,int nn) { return mm > nn ? mm : nn ; }
- int dosth()
- {
- memset(vis,0,sizeof(vis));
- set<int> st;
- int i , j , k , ans ;
- for ( i = 0 , ans = 1 ; i < n ; i++)
- {
- for ( j = 0 ; j < n ; j++)
- {
- if( i != j && !vis[i][j] )
- {
- st.clear();
- st.insert(i);
- st.insert(j);
- for ( k = 0 ; k < n ; k++) if( k != i && k != j )
- {
- if( ( yy[j] - yy[i] ) * ( xx[k] - xx[j] ) == ( yy[k] - yy[j] ) * ( xx[j] - xx[i] ) )
- {
- st.insert(k);
- }
- }
- ans = get_max(ans,st.size());
- set<int>::iterator ite1,ite2 ;
- for ( ite1 = st.begin() ; ite1 != st.end() ; ite1++)
- {
- ite2 = ite1 ;
- ite2++;
- for ( ; ite2 != st.end() ; ite2++)
- {
- if( *ite1 != *ite2 )
- {
- vis[*ite1][*ite2] = vis[*ite2][*ite1] = 1 ;
- }
- }
- }
- }
- }
- }
- return ans ;
- }
- void solve()
- {
- int i , j , ans ;
- for( i = 0 ; i < n ; i++) { increa[i] = 0.1 * a[i] ; increb[i] = 0.1 * b[i] ; }
- for ( i = 0 , ans = 1 ; i <= 10 ; i++)
- {
- for( j = 0 ; j < n ; j++) { xx[j] = increa[j] * i + x[j] ; yy[j] = increb[j] * i + y[j] ; }
- ans = get_max(ans,dosth());
- }
- printf("%d\n",ans);
- }
- int main()
- {
- int i ;
- while (~scanf("%d",&n))
- {
- for( i = 0 ; i < n ; i++) scanf("%d%d%d%d",&x[i],&y[i],&a[i],&b[i]);
- solve();
- }
- }
水平有限,不能保證分析和代碼都正確。