hdu3585 二分最大团(dp优化)
? ? ? 給你一些點( <= 50),讓你找到k個點,使得他們之間的最小距離最大。
思路:
? ? ? 求最小的最大,我們可以直接二分去枚舉距離,但是要注意,不要去二分double找距離,要知道,最后的答案肯定是其中某個點的兩點距離,所以我們直接把所有點的距離求出來,放一個數組里面,然后sort下,然后去二分這個數組的下標,根據下標找距離,這樣可以節省點時間(這種情況這針對于某些題目,如果點非常多,n*(n-1)/2距離的種類是有可能很多,這樣還不如直接二分double快點,畢竟二分是log級別的),二分的時候我們可以根據最大團來判斷當前最大團是否大于等于k,來看當前距離是不是滿足要求,在簡單說一下在這個題目里用最大團要注意的東西,首先最大團是NP問題,求他是很費時間的,平時我常用的就是搜索+dp優化,hdu1530是模板題目,我自己看了最大團的思路后直接自己模擬一個4000+ms AC了,但是在這個題目里,直接各種TLE,因為自己模擬的那個沒有dp優化,做這個題目必須dp優化,不然會死的很慘。還有就是有的人看到最大團,或者最大獨立集元素個數就直接想著用 二分匹配去做(之前我就是)但是大家一直忽略了一個問題,就是二分匹配的前提是題目給的是二分圖,大家經常忽略了題目給的是不是二分圖,而直接套定義所以會直接 一遍匈牙利 然后各種wa。二分圖的最大團,或者最大獨立集可以 匈牙利 但是不是二分圖的就直接是 NP問題,就只能用本方法去殼,但要記得dp優化什么的。
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm>#define N 60 using namespace std;typedef struct {double x ,y; }NODE;NODE node[N]; int n ,k ,Ans; int map[N][N] ,now[N]; int dp[N]; double dis[N][N] ,num[N*N];void DFS(int x ,int sum) {if(sum > Ans) Ans = sum;if(Ans >= k) return;int able = 0;for(int i = x + 1 ;i <= n ;i ++)if(now[i]) able ++;if(able + sum <= Ans) return;int tnow[N];for(int i = x + 1 ;i <= n ;i ++)tnow[i] = now[i];for(int i = x + 1 ;i <= n ;i ++){if(!tnow[i]) continue;if(dp[i] + sum <= Ans) continue;for(int j = x + 1 ;j <= n ;j ++)now[j] = tnow[j] & map[i][j];DFS(i ,sum + 1);} }int jude(int mid) {for(int i = 1 ;i <= n ;i ++)for(int j = i + 1 ;j <= n ;j ++)if(num[mid] <= dis[i][j])map[i][j] = map[j][i] = 1;else map[i][j] = map[j][i] = 0;Ans = dp[n] = 1;for(int i = n - 1 ;i >= 1 ;i --){for(int j = 1 ;j <= n ;j ++)now[j] = map[i][j];DFS(i ,1);dp[i] = Ans;if(Ans >= k) return 1;}return 0; }double get_dis(NODE a ,NODE b) {double x = (a.x - b.x) * (a.x - b.x);double y = (a.y - b.y) * (a.y - b.y);return sqrt(x + y); }int main () {int i ,j ,t;while(~scanf("%d %d" ,&n ,&k)){for(i = 1 ;i <= n ;i ++)scanf("%lf %lf" ,&node[i].x ,&node[i].y);for(t = 0 ,i = 1 ;i <= n ;i ++){for(j = i + 1 ;j <= n ;j ++){dis[i][j] = dis[j][i] = get_dis(node[i] ,node[j]);num[++t] = dis[i][j];}dis[i][i] = 0;}sort(num + 1 ,num + t + 1);int low = 1 ,up = t ,mid ,ans =1;while(low <= up){mid = (low + up) >> 1;if(jude(mid)){low = mid + 1;ans = mid;}else up = mid - 1;}printf("%.2lf\n" ,num[ans]);}return 0; }
總結
以上是生活随笔為你收集整理的hdu3585 二分最大团(dp优化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu1530 最大团简单题目
- 下一篇: 对最大团的理解