下面是在《算法之道》上看到的思维题,感觉很简单,就敲了敲,没写算法题也有一段时间了。现在又做做算法题,感觉真的很喜欢搞算法。大牛曾说,程序是蓝色的诗,算法是诗的灵魂。
给出一堆球的质量,已知有一个与众不同为所有中最轻的,其余质量相等。给出一个天平,称出这个。由于只给出了天平,就不能直接一次循环挑选出其中的最小值。可以尝试二分‘、三分。下面直接贴个程序:
#include<iostream> #include<ctime> using namespace std; const int MAXN=10000; int nCount; int wei[MAXN],sum[MAXN]; int threeDfs(int left,int right) { nCount++; if(0==right-left) return left; else if(1==right-left) return wei[left]<wei[right]?left:right; int n=right-left+1; int lMid=left+n/3; if(2==n%3) lMid++; int rMid=lMid+n/3; if(2==n%3) rMid++; int lSum; if(0==left) lSum=sum[lMid-1]; else lSum=sum[lMid-1]-sum[left-1]; int mSum=sum[rMid-1]-sum[lMid-1]; int rSum=sum[right]-sum[rMid-1]; if(lSum>mSum) return threeDfs(lMid,rMid-1); else if(lSum<mSum) return threeDfs(left,lMid-1); return threeDfs(rMid,right); } int twoDfs(int left,int right) { nCount++; if(0==right-left) return left; else if(1==right-left) return wei[left]<wei[right]?left:right; int n=right-left+1; int lSum; int rSum; int mid=left+n/2; if(0==left) lSum=sum[mid-1]; else lSum=sum[mid-1]-sum[left-1]; rSum=sum[right]-sum[mid-1]; if(1==n%2) rSum-=wei[right]; if(lSum>rSum) return twoDfs(mid,right); else if(lSum<rSum) return twoDfs(left,mid-1); return right; } void solve(int n) { sum[0]=wei[0]; for(int i=1;i<n;i++) sum[i]=sum[i-1]+wei[i]; cout<<endl<<"二分法结果如下:"<<endl; nCount=0; int ans=twoDfs(0,n-1); cout<<"经过"<<nCount<<"次,找到最轻的一个是第"<<ans<<"个,重为"<<wei[ans]<<endl; cout<<endl<<"三分法结果如下:"<<endl; nCount=0; ans=threeDfs(0,n-1); cout<<"经过"<<nCount<<"次,找到最轻的一个是第"<<ans<<"个,重为"<<wei[ans]<<endl; } void init(int n) { for(int i=0;i<n;i++) wei[i]=10; int id=rand()%n; wei[id]=5; cout<<"最轻的一个是第"<<id<<"个,重为"<<wei[id]<<endl; } int main() { int n; srand((unsigned int)(time(NULL))); do { n=rand()%MAXN; } while(0==n); cout<<"总共有"<<n<<"个球"<<endl; init(n); solve(n); return 0; }
下面是运行结果: