1001 哈密顿绕行世界问题
水题
int m ; bool vis[100]; int aa = 0 ; int mm[50][50]; int dp[100]; void dfs(int now , int nn) { dp[nn] = now; if(nn == 19) { if(mm[now][m]) { cout <<aa<<": "; for (int i = 0 ;i < 20 ;i ++) cout <<" "<<dp[i]; cout <<" "<<m<<endl; aa ++ ; } } for (int i = 1 ;i <= 20 ;i ++) if(mm[now][i]) { if(!vis[i]) { vis[i] = 1 ; dfs(i, nn + 1 ); vis[i] = 0 ; } } } int main() { mem(mm,0); for (int i = 1 ; i <= 20 ; i ++ ) { int a ,b , c ; cin >> a >> b >> c ; mm[i][a] = 1 ; mm[i][b] = 1 ; mm[i][c] = 1 ; } while(scanf("%d",&m) ,m ) { aa = 1 ; mem(dp,0); mem(vis,0); vis[m] = 1 ; dfs(m,0); } return 0; }1002 Red and Black
水题
bool vis[100][100]; char mm[100][100]; int n , m ; int xx[4] = {0 ,0 ,1 ,-1}; int yy[4] = {1,-1,0,0}; int inmap(int x,int y ) { if(x >= 0 &&x < m &&y >= 0 &&y < n)return 1; return 0; } void dfs(int x ,int y ) { for (int i = 0 ;i < 4 ; i ++) { int tx = x + xx[i]; int ty = y + yy[i]; if(inmap(tx,ty)&&!vis[tx][ty]&&mm[tx][ty] != '#') { vis[tx][ty] = 1 ; dfs(tx,ty); } } } int main() { while(scanf("%d%d",&n,&m) ,(m + n )) { mem(vis,0); for (int i = 0 ;i < m ;i ++){ scanf("%s",mm[i]); } for (int i = 0 ;i < m ;i ++) { for (int j = 0 ;j < n ;j ++) if(mm[i][j] == '@') { vis[i][j] = 1 ; dfs(i,j); break; } } int ans = 0 ; for (int i = 0 ;i < m ;i ++) { for (int j = 0 ;j < n ;j ++) if(vis[i][j]) ans ++; } cout <<ans <<endl; } }
水题
int n , m ; char mm[105][105]; int xx[8] = {0,0,1,-1,1,1,-1,-1}; int yy[8] = {1,-1,0,0,1,-1,1,-1}; bool vis[105][105]; int inmap(int x,int y) { if(x >= 0 &&x < n &&y >= 0 &&y < m && mm[x][y] != '*') return 1; return 0; } void dfs(int x, int y ) { for (int i = 0 ;i < 8 ;i ++) { int tx = x + xx[i]; int ty = y + yy[i]; if(inmap(tx,ty)&&!vis[tx][ty]) { vis[tx][ty] = 1; dfs(tx,ty); } } } int main() { while(scanf("%d%d",&n,&m) , (n + m )) { for (int i = 0 ;i < n ;i ++) scanf("%s",mm[i]); int ans = 0 ; mem(vis,0); for (int i = 0 ;i < n ;i ++) { for (int j = 0 ;j < m; j ++) { if(mm[i][j] == '@' && !vis[i][j]) { ans ++; dfs(i,j); } } } cout <<ans <<endl; } }
水题
double cal(double x) { double c = 8 * x * x * x * x + 7 * x * x * x + 2 * x * x + 3 * x + 6 ; return c; } int main() { int T; cin >> T; while( T -- ) { double x ; cin >> x ; if(x < cal(0.0) || x > cal(100.0)) { printf("No solution!\n"); } else { double low = 0 ,high = 100; double mid = (low + high) / 2 ; while(high - low > 1e-11) { mid = (high + low ) / 2 ; double cc = cal(mid); if(cc == x) break; if(cc < x) low = mid ; else high = mid ; } mid = (high + low) / 2 ; printf("%.4f\n",mid); } } }1005 Selecting Problems
题意:就是给你一些人,每个人都能做一些题目,然后给出一个人数限制k,问至少有k个人都会做同样的题,问这个题数最大是多少。
思路:题目中给出的题目总数m <= 15,所以可以用二进制表示一个人会做那些题目。
可以先预处理出0 - 2^15 的题目作法 。
这里就发生了做这道题最悲剧的一件事,我直接把每道题扔进一个vector里,想也没想就开始二分了。
然后TLE。我就开始改二分的条件,想着估计是哪个状态没跳出,在mid 那里处理的不好。所以就开始了我的狂T之旅。
贴上vector的预处理。
for (int i = 0 ;i < 1<<15 ; i ++) { int num = i ; int ans = 0 ; while( num ) { if(num & 1 ) ans ++; num /= 2; } qq[ans].push_back(i); }好不容易想到把vector改成数组好了。
for (int i = 0 ; i < 1<<15 ; i ++) { int num = i ; int ans = 0 ; while( num ) { if(num & 1 ) ans ++; num /= 2; } qq[ans][f[ans] ++] = i ; }
然而悲剧的事情还没结束。
因为还是T。。。然后我又陷入了狂改mid值的过程当中。。。期间T了无数次。
然后不知道啥想法,我就把交代码的语言改成GUN C ++ .(我这边一直默认是交Visual C++)。。
然后就A了。。。
A了。。。
了。。。
PS:亲测换了语言后如果用vector也是T 。今天你被坑了吗?
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 2005 #define inf 1<<28 #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define FOR(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) using namespace std; string st; int q[1005]; int n , m , k, ans ; bool vis[1005]; int qq[20][1<<16]; char ddd[25]; int f[20]; int main() { //mem(f,0); //mem(qq,0); for (int i = 0 ; i <= 1<<15 ; i ++) { int num = i ; int ans = 0 ; while( num ) { if(num & 1 ) ans ++; num /= 2; } qq[ans][f[ans] ++] = i ; } while(scanf("%d%d%d",&n,&m,&k) != EOF) { mem(q,0); ans=0; for (int i = 0 ; i < n ; i ++) { int a ; scanf("%s",ddd); scanf("%d",&a); while(a -- ) { int x ; scanf("%d",&x); x --; q[i] |= 1 << x; } } int low = 0 ,high = m ; while(high >= low) { int mid = (high + low) / 2 ; int num ; int l = f[mid]; for (int i = 0 ; i < l; i ++) { num = 0 ; for (int j = 0 ; j < n ; j ++) { if((q[j] & qq[mid][i]) == qq[mid][i]) num ++; } if(num >= k) { ans = mid ; low = mid + 1 ; break; } } if(low <= mid) high = mid - 1 ; } printf("%d\n",ans); } return 0; }
最长距离肯定是子弹的最大射击距离,二分时间,找出最短的时间可以射击到敌人。
double xx1,yy1,xx2,yy2,lx,ly,vd,vb,l; int main() { while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&xx1,&yy1,&xx2,&yy2,&lx,&ly,&vd,&vb,&l)) { if(xx1 == 0 && xx2 == 0 && yy1 == 0 && yy2 == 0 && lx == 0 && ly ==0 && vd == 0 && vb == 0 && l ==0 ) return 0; double ftime = (double)l / (double)vb ;//子弹飞的时间 double left = ftime ,right = 1e7; double mid = (left + right ) / 2 ; while(right - left > 1e-11) { mid = (left + right ) / 2 ; double nowx = xx1 + lx * mid ;//敌人当前位置 double nowy = yy1 + ly * mid ; double dis = sqrt((xx2 - nowx) * (xx2 - nowx ) + (yy2 - nowy ) * (yy2 - nowy));//俩人的距离 double dis1 = (mid - ftime) * vd ;//需要跑的距离 if(dis1 >= fabs(dis - l)) right = mid ; else left = mid ; } mid = (left + right ) / 2; printf("%.3f %.3f\n",l,mid); } }
1007 Dome of Circus
三分圆锥的高,求出体积的最小值。记录高和半径。
double a[Max],b[Max],c[Max]; int main() { int T ; cin >> T; while ( T -- ) { int n ; cin >> n ; for(int i = 0 ; i < n ; i ++)scanf("%lf%lf%lf",a + i ,b + i ,c + i ); double l = 0 , r = 10000 ; double h = inf , rr = inf; double ansarea = inf; while(r - l > 1e-11) { double mid = (l + r ) / 2; double midd = (r + mid ) / 2 ; double mr = 0 ; double mmr = 0; for (int i = 0 ; i < n ; i ++) { double mm = sqrt(a[i] * a[i] + b[i] * b[i])* mid / (mid - c[i]);//根据比例关系,求出底面半径 double mmm = sqrt(a[i] * a[i] + b[i] * b[i])* midd / (midd - c[i]); if(mr < mm) mr = mm ;//更新半径的最大值 if(mmr < mmm )mmr = mmm; } double ansmid = mr * mr * PI * mid / 3 ; double ansmidd = mmr * mmr * PI * midd / 3 ; if(ansarea > ansmid) { ansarea = ansmid; h = mid; rr = mr; } if(ansarea > ansmidd) { ansarea = ansmidd ; h = midd; rr =mmr ; } if(ansmid > ansmidd) { l = mid ; } else { r = midd; } } printf("%.3f %.3f\n",h,rr); } }1008 Turn the corner
三分角度,求出最大的过弯y,最后比较判断。
一开始很sb的直接把角度带进三角函数里计算。。。忘了化成pi
double cal(double n ,double x ,double l ,double d) { double xx,yy,c,s; s = sin(n); c = cos(n); xx = -1 * (d / s + c * l) ; yy = ( d / c + s * l ) ; double tmp = ( 1.0 - x / yy ) * xx * (-1); return tmp; } int main() { double l ,d , x , y ; while(cin >> x >> y >> l >> d) { double low = 0 , high = 90.0 ; double ans = 0 ; while( high - low > 1e-8) { double mid = (low + high) / 2 ; double midd = (low + mid ) / 2 ; double amid = cal(mid * PI / 180,x,l,d); double amidd = cal(midd * PI / 180,x,l,d); ans = max(ans,max(amid,amidd)); if(amid > amidd) { low = midd; } else high = mid ; } if(ans > y) cout <<"no"<<endl; else cout <<"yes"<<endl; } }
红色部分是两个二次函数的最大部分,然后最下面那个点就是最小值。所以同样可以用三分求解。
double a[Max],b[Max],c[Max]; double cal(double aa,double bb ,double cc,double xx) { double dd = aa * xx * xx + bb * xx + cc; return dd; } int main() { int T ; cin >> T ; while( T -- ) { int n ; cin >> n ; for (int i = 0 ;i < n ;i ++ ) scanf("%lf%lf%lf",a + i ,b + i ,c + i); double l = 0 ; double r = 1000.0; double mid = (l + r) / 2 ; double ansy = inf; while( r - l > 1e-11) { mid = (l + r ) / 2 ; double midmid = (mid + r ) / 2 ; double ansmid = -inf ;//一开始这个初值赋成0。。然后就又悲剧了,太粗心了。 double ansmidmid = -inf ; for (int i = 0 ; i < n ;i ++) { double mm = cal(a[i],b[i],c[i],mid); double mmm = cal(a[i],b[i],c[i],midmid); if(ansmid < mm)ansmid = mm; if(ansmidmid < mmm) ansmidmid = mmm; } ansy = min(ansy,min(ansmid,ansmidmid)); if(ansmid > ansmidmid) l = mid; else r = midmid; } printf("%.4f\n",ansy); } }1010 湫湫系列故事——设计风景线
接下来介绍这道传说中的坑王之王。
这道题是腾讯马拉松的题,那天比赛的时候我还和学长讨论了一下。问题就集中在这个最长路径,他和我说就是最长路,我说可以是树啊。这个最长路径当时就很迷茫了。赛后去看了 解题报告,写的都是水并查集,然后求最大生成树,然后找出最大值。
当时我就在YY,早知道我就写这道题了。。。(因为题意不明确,当时我就去做1002了,赛后发现是神题。。。)
好了,回到这次比赛的这道题。。
又一次看到这道题,我想都没想直接并查集敲上去,10分钟不到就交了。然后就WA了。。之后改改交交WA了5, 6次之后。。我就觉得不对了。。
我已经完全可以证明我的思路是正确的了。
然后我就出去找到了原题HDU4514 。才发现DISCUSS里面说题意已经改了。。。改成求最长路了。。。
当时我就被雷的里焦外嫩,果然是神坑。
然后就开始重新写了 。
1.判环,我就没改,直接并查集,物尽其用了。
2.找最长路,这部分我一开始用spfa,但是敲着敲着就跑不出来了。。
3.然后我就发现一种很神的办法,就是求树的直径。
树上的最长路就是树的直径。然后可以用两遍BFS解决。
先在这颗树里随意找一点进行BFS,找出最长路的那个节点。
然后对这个节点进行一次BFS,找出的最长路即为这棵树的最长路,也就是直径。
算法正确性证明见:http://blog.sina.com.cn/s/blog_77dc9e0801015m8z.html
4.这道题让我跪了N次的地方,就是我发现居然会MLE。。。
5.然后我就开始各种改数组,还是MLE,只好将判环的并查集改了,将那几个数组都去了。然后用DFS进行判环。
6.这次没MLE了,但是栈溢出了。加了个外挂。然后还是溢出。
7.这次和1005那题是一样的坑,我随手换了个语言Visual C++ 就A了(因为做完1005我就把默认语言改成GUN C++了,而用这个交一直爆栈)。。
这就是这道题的集锦。。下面贴代码
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 10001 #define inf 1<<28 #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define FOR(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #pragma comment(linker, "/STACK:10240000000000,10240000000000") using namespace std; struct kdq { int e ,l ,next; } ed[Max * 200]; int head[Max * 10] ; int num ; int vis[Max * 10] ; int dis[Max * 10] ; int ans = 0 ; void add(int s,int v ,int l) { ed[num].e = v ; ed[num].l = l ; ed[num].next = head[s]; head[s] = num ++ ; } void init() { mem(head,-1); num = 0 ; mem(dis,0); ans = 0 ; } int dfs(int now ,int pre) { vis[now] = 1 ; for (int i = head[now ]; i != -1 ; i = ed[i].next) { int v = ed[i].e ; if(v != pre) { if(vis[v]) return 0 ; if(dfs(v ,now) == 0) return 0; } } return 1 ; } bool vis1[Max * 10] ; void bfs(int now ) { mem(vis1,0); vis1[now] = 1 ; dis[now] = 0 ; queue<int>qe; qe.push(now);//任选一个节点进行BFS //qe[0] = now ; int v = now ; int vv = dis[now] ; while(!qe.empty()) { int tt = qe.front(); //int tt = qe[l ++ ]; qe.pop(); for (int i = head[tt] ; i != -1 ; i = ed[i].next) { int t = ed[i].e ; int tl = ed[i].l ; if(!vis1[t]) { dis[t] = dis[tt] + tl ; vis1[t] = 1 ; if(vv < dis[t]) vv = dis[t] , v = t ;//找出最长路的节点 //qe[r ++ ] = t ; qe.push(t) ; } } } //if(ans < vv) ans = vv ; //mem(vis,0); while(!qe.empty())qe.pop(); qe.push(v);//对这个节点再进行一次BFS vis[v] = 1; dis[v] = 0 ; while(!qe.empty()) { int tt = qe.front() ; qe.pop() ; for (int i = head[tt] ; i != -1 ; i = ed[i].next) { int t = ed[i].e ; int tl = ed[i].l ; if(!vis[t]) { dis[t] = dis[tt] + tl ; vis[t] = 1 ; if(ans < dis[t])ans = dis[t] ; qe.push(t) ; } } } } int main() { int n , m ; while(scanf("%d%d",&n,&m) != EOF) { //for (int i = 0 ; i <= n ; i ++)f[i] = i ; init(); for (int i = 0 ; i < m ; i ++) { int a , b, c ; scanf("%d%d%d",&a,&b,&c); add(a,b,c) ; add(b,a,c) ; } bool flag = 0; mem(vis,0); for (int i = 1; i <= n ; i ++) if(!vis[i]) { if(dfs(i , -1 ) == 0)//dfs判环 { flag = 1 ; break; } } if(flag) { cout <<"YES"<<endl; continue; } mem(vis,0) ; int k ; for (int i = 1 ; i <= n ; i ++) { if(!vis[i]) { bfs(i); } } printf("%d\n",ans); } } /* 4 3 1 2 1 2 3 1 3 4 1 */