菜鸟的思考步骤:
1.设定当前时间为0,鱼往负方向游,这样可以把每个鱼看成在时间轴上的一个线段。t[a]=3,l[a]=4的鱼,看成是线段[3,7]。我们只需要确定找到两个点,使得抓到的鱼最多就行。
2.首先想到的是找到两个公共线段A,B,使得在A,B处的鱼的鱼最多(当然得除去重复的)。
3.公共线段上的时间点使等价的,这里可以用线段的顶点来表示该线段(因为线段的顶点一定是某个“鱼线段”的端点,想想还是能明白)。
4.这样先把所有“鱼线段”的端点收集起来,然后随机选两个不同的点,算出与这两个点处的鱼数,找到其中最大的那个即可。
5.时间复杂度:O((2n)^2*n)=O(n^3),算法多项式时间内有解。
菜鸟改过好多次的代码:
import java.util.*; import java.util.regex.*; import java.text.*; import java.math.*; public class EelAndRabbit { public int getmax(int[] l, int[] t) { int len = t.length; int[] point = new int[2*len]; int i,j,k,max,tmp; //搜集所有端点 for(i=0;i<len;i++){ point[2*i]=t[i]; point[2*i+1]=t[i]+l[i]; } //遍历端点,找出捕鱼的最大值 max=0; for(i=0;i<len+len;i++){ for(j=i+1;j<len+len;j++){ if(point[i]==point[j])//注意这两个端点不能一样 continue; tmp=0; for(k=0;k<len;k++){ if(checkIn(point[i],t[k],t[k]+l[k])||checkIn(point[j],t[k],t[k]+l[k])) tmp++; } if(tmp>max) max=tmp; } } return max; } private boolean checkIn(int point,int left,int right){ return point>=left&&point<=right; } } //Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!
大神的代码java:
public class EelAndRabbit { public int getmax(int[] l, int[] t) { int cnt = l.length; int res = 0; if(cnt <= 2) return cnt; for(int i=0; i<cnt; i++) for(int j=i+1; j<cnt; j++) { int ta = t[i]; int tb = t[j]; int catchcnt = 0; for(int k=0; k<cnt; k++) { if((t[k]<=ta && t[k]+l[k] >= ta) || (t[k]<=tb && t[k]+l[k] >= tb)) catchcnt++; } if(catchcnt > res) res = catchcnt; } return res; } }
大神的代码C++:
#include <algorithm> #include <iostream> #include <sstream> #include <string> #include <vector> #include <queue> #include <cstring> #include <cassert> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cctype> #include <cmath> using namespace std; class EelAndRabbit { public: int getmax (vector <int> l, vector <int> t); }; int EelAndRabbit::getmax (vector <int> l, vector <int> t) { int res=0; int n = l.size(); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { set<int> s; int T = t[i]; for (int k = 0; k < n; ++k) { int head = T-t[k]; int tail = T-t[k]-l[k]; if (head >= 0 and tail <= 0) { s.insert(k); } } T = t[j]; for (int k = 0; k < n; ++k) { int head = T-t[k]; int tail = T-t[k]-l[k]; if (head >= 0 and tail <= 0) { s.insert(k); } } res = max(res,(int)s.size()); } } return res; } // Powered by FileEdit // Powered by CodeProcessor
分析:
算法: Brute Force
大神代码分析:
1.大神们都只考虑了鱼头端点,而我还考虑了鱼尾。
仔细想想,貌似我真的多虑了:公共线段的“尾端”必定为"鱼尾点",“顶端”必定为“鱼头点”。想象一条公共线段CD在AB内移动,D点最多是和B点重合,而C点最多是和A点重合。
2.虽然C++大神用的set不太高效,但set用起来还是那么方便,学习了。