不想一篇blog太长了,所以再来一篇写day1。
I - 棋盘问题
Input
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
Sample Input
2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1
Sample Output
2 1
这道题用的是深度优先搜索dfs,题目要求每行每列不能有重复的棋子,所以就bfs每一行(i),然后遍历该行的每一列,如果是‘#’且满足行列均不重复,则可以放在这,放下以后接着下一行dfs(i+1),如果该行没有可以放置棋子的位置,则return到上一行。边界就是手中的棋子刚好放完。
贴代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 char a[9][9]; 7 int vis[9];//判断这一列是否放了棋子。 8 int n,k,sum,m; 9 void dfs(int i) 10 { 11 if(m==k){sum++;return;}//棋子放完了,结果+1,return回去寻找新的方案。 12 if(i>n)return;//行数越界要返回 13 for(int j=1;j<=n;j++)//开始遍历当前行的每一列 14 { 15 if(a[i][j]=='#'&&vis[j]==0)//如果这个点是‘#’且该列没有棋子,则放下棋子 16 { 17 m++;//放下的棋子数+1 18 vis[j]=1;//这个点标记 19 dfs(i+1);//递归下一行 20 m--;//回来后棋子回到手上 21 vis[j]=0;//取消这一列的标记 22 } 23 } 24 dfs(i+1);//这一行没得放继续下一行 25 } 26 int main() 27 { 28 memset(vis,0,sizeof(vis)); 29 while(cin>>n>>k&&(n!=-1&&k!=-1)) 30 { 31 sum=m=0; 32 for(int i=1;i<=n;i++) 33 for(int j=1;j<=n;j++)cin>>a[i][j]; 34 dfs(1); 35 cout<<sum<<endl; 36 } 37 }
J - Sudoku
Input
Output
Sample Input
1 103000509 002109400 000704000 300502006 060000050 700803004 000401000 009205800 804000107
Sample Output
143628579 572139468 986754231 391542786 468917352 725863914 237481695 619275843 854396127
这道题是一道数独题,接着上一题的思考,我马上就有思路了,dfs!就是把1~9这9个数放进格子嘛,如果满足行、列、小九宫格不重复
就可以放进去,所以我就开了三个数组,来分别判断行、列、小九宫格内已经存放的数字。还是dfs,不过这里是搜索每一个格子,遍历1~9
这9个数,看看哪个数可以放进去,放进去就接着放下一个空,否则return回去前面放过的空重新放。
具体细节请看代码:
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int t; 5 char a[10][10];//用char来储存数独是为了方便输入 6 int row[10][10],column[10][10];//判断行和列的已经放下的数字 7 int sq[4][4][10];//判断小九宫格里面已经放下的数字 8 int flag=0;//储存结果 9 int csq(int i)//这个函数是放在sq里面做下标的,用来判断当前格子在哪个小九宫格 10 { 11 if(i<=3)return 1; 12 else if(i<=6)return 2; 13 else if(i<=9)return 3; 14 return 0; 15 } 16 bool check(int i,int j,int k)//判断是否可以放下这个数字 17 { 18 if(row[i][k]==0&&column[j][k]==0&&sq[csq(i)][csq(j)][k]==0)return true; 19 return false; 20 } 21 int dfs(int x,int y) 22 { 23 if(x>9||y>9)//先判断是否越界 24 { 25 flag=1; 26 return 0; 27 } 28 if(a[x][y]!='0') 29 { 30 if(y==9)dfs(x+1,1);//如果这个位置已经有了非零数字,就搜下一个 31 else dfs(x,y+1); 32 } 33 else 34 { 35 for(int k=1;k<=9;k++)//在9个数中找出可以放入的数 36 { 37 if(check(x,y,k)) 38 { 39 a[x][y]=k+'0';//放入这个数 40 row[x][k]=1;column[y][k]=1;sq[csq(x)][csq(y)][k]=1;//标记 41 if(y==9)dfs(x+1,1);//继续搜索下一个 42 else dfs(x,y+1); 43 if(flag)return 0;//如果完成了数独,则结束 44 a[x][y]='0';//否则取消标记,继续搜这个位置的数 45 row[x][k]=0;column[y][k]=0;sq[csq(x)][csq(y)][k]=0; 46 } 47 } 48 return 0;//9个数都搜完了,没有合适的,就返回去修改前面错误的数 49 } 50 } 51 int main() 52 { 53 int n; 54 cin>>n; 55 for(int t=0;t<n;t++) 56 { 57 memset(row,0,sizeof(row)); 58 memset(column,0,sizeof(column)); 59 memset(sq,0,sizeof(sq)); 60 for(int i=1;i<=9;i++) 61 { 62 for(int j=1;j<=9;j++) 63 { 64 cin>>a[i][j]; 65 if(a[i][j]!='0')//对输入的数做好标记 66 { 67 row[i][a[i][j]-'0']=1; 68 column[j][a[i][j]-'0']=1; 69 sq[csq(i)][csq(j)][a[i][j]-'0']=1; 70 } 71 } 72 } 73 flag = 0; 74 dfs(1,1); 75 for(int i=1;i<=9;i++) 76 { 77 for(int j=1;j<=9;j++)cout<<a[i][j]; 78 cout<<endl; 79 } 80 } 81 return 0; 82 }
K - 迷宫问题
int maze[5][5] = {它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
Input
Output
Sample Input
0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0
Sample Output
(0, 0) (1, 0) (2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (3, 4) (4, 4)
这道题就不能用bfs了,我一来就用dfs做,只能得到最少步数,无论怎样都得不到路径,经过漫长的思考 (百度),终于用广度优先搜索bfs解决了问题,bfs我是在《啊哈算法》里面彻底搞懂的。
1 #include<iostream> 2 using namespace std; 3 4 struct node 5 { 6 int x,y;//这个点的坐标 7 int fa;//父点 8 int step;//到这个点的最短步数 9 }; 10 struct node q[26]; 11 int vis[5][5]={0}; 12 int head=1,tail=1,px=0,py=0;//head是队列的头部,tail是尾部,最先放入的在头部 13 int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//方向数组便于搜索 14 int maze[5][5]; 15 void bfs() 16 { 17 q[head].x=0;q[head].y=0;q[head].step=0;q[head].fa=0;//从(0,0)开始搜索 18 tail++; 19 vis[px][py]=1;//记得标记第一个点 20 int result = 0; 21 while(head<tail)//head==tail的时候已经搜索了所有的点了 22 { 23 for(int i=0;i<4;i++)//尝试从这个点出发到四个方向的点 24 { 25 px=q[head].x+dir[i][0]; 26 py=q[head].y+dir[i][1]; 27 if(px<0||py<0||px>4||py>4)continue;//越界则换方向 28 if(vis[px][py]==0&&maze[px][py]==0)//往这个方向走的点,没有标记且不是”墙“ 29 { 30 vis[px][py]=1;//标记这个点 31 q[tail].x=px;//压入队列 32 q[tail].y=py; 33 q[tail].fa=head;//记录这个点的父点 34 q[tail].step=q[head].step+1;//到这个点的步数是到父点的步数+1 35 tail++;//尾部加长,继续搜索 36 } 37 if(px==4&&py==4)//搜到了终点 38 { 39 result = 1; 40 break; 41 } 42 } 43 head++;//这个点能一步到达的所有点搜完以后搜下一个点 44 if(result)break; 45 } 46 } 47 48 int main() 49 { 50 for(int i=0;i<5;i++) 51 for(int j=0;j<5;j++)cin>>maze[i][j]; 52 bfs(); 53 int c=tail-1,i=0; 54 struct node t[20];//反过来存路径,因为路径要正着打印 55 while(c!=0) 56 { 57 t[i].x=q[c].x; 58 t[i].y=q[c].y; 59 i++; 60 c=q[c].fa; 61 } 62 for(int j=i-1;j>=0;j--)cout<<"("<<t[j].x<<", "<<t[j].y<<")"<<endl;//这逗号后面有个空格可真的是考眼力啊 63 }
L - Catch That Cow
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
5 17Sample Output
4
这道题的题意就是从点x到点y,一步只能从x点到x+1,x-1或x*2,求x到y的最少步数。我一开始在想这是不是贪心啊,但找不到最优子解,就很难受,最后还是百度了。知道这个是bfs以后我瞬间醒悟,马上自己就敲出来了。 (做出来以后觉得这就是bfs啊太明显了把)
1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 struct node{//结构体记录点坐标和到这个点的最短步数 6 int x; 7 int step; 8 }t,p,temp; 9 queue<struct node>q; 10 int vis[100005]; 11 int next(int n,int k)//这个函数是用来方便for一次性遍历下一步操作的 12 { 13 if(k==0)return n+1; 14 if(k==1)return n-1; 15 if(k==2)return n*2; 16 return 0; 17 } 18 bool check(struct node u)//判断这个点是否找过 19 { 20 if(u.x<0||u.x>100000||vis[u.x]==1)return false; 21 return true; 22 } 23 int bfs(int n,int m) 24 { 25 while(!q.empty())q.pop();//开始之前一定要把队列清空 26 t.x=n;t.step=0; 27 vis[n]=1; 28 q.push(t);//放入第一个点 29 if(n==m)return 0;//起点和终点一样就是0步咯 30 while(!q.empty()) 31 { 32 p=q.front(); 33 q.pop(); 34 for(int k=0;k<3;k++)//搜索当前点一步能到的点 35 { 36 temp.x=next(p.x,k); 37 temp.step=p.step+1;//到子点的步数是父点为父点步数+1 38 if(temp.x==m)return temp.step;//到了终点直接输出结果结束。 39 if(check(temp))//否则如果这个点没访问过,就放入队列 40 { 41 q.push(temp); 42 vis[temp.x]=1; 43 } 44 } 45 } 46 return 0; 47 } 48 int main() 49 { 50 int n,m; 51 while(cin>>n>>m) 52 { 53 memset(vis,0,sizeof(vis)); 54 cout<<bfs(n,m)<<endl; 55 } 56 return 0; 57 }
M- 三分(离散)
You are given a multiset S consisting of positive integers (initially empty). There are two kind of queries:
- Add a positive integer to S, the newly added integer is not less than any number in it.
- Find a subset s of the set S such that the value is maximum possible. Here max(s) means maximum value of elements in s, — the average value of numbers in s. Output this maximum possible value of .
The first line contains a single integer Q (1 ≤ Q ≤ 5·105) — the number of queries.
Each of the next Q lines contains a description of query. For queries of type 1 two integers 1 and x are given, where x (1 ≤ x ≤ 109) is a number that you should add to S. It's guaranteed that x is not less than any number in S. For queries of type 2, a single integer 2 is given.
It's guaranteed that the first query has type 1, i. e. S is not empty when a query of type 2 comes.
OutputOutput the answer for each query of the second type in the order these queries are given in input. Each number should be printed in separate line.
Your answer is considered correct, if each of your answers has absolute or relative error not greater than 10 - 6.
Formally, let your answer be a, and the jury's answer be b. Your answer is considered correct if .
6
1 3
2
1 4
2
1 8
2
0.0000000000
0.5000000000
3.0000000000
4
1 1
1 4
1 5
2
2.0000000000
标题都说了三分,可我还是一点思路都没有。后来百度,看了n久才看懂,害。
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 using namespace std; 5 const int MAXN=5e5+5; 6 #define eps 1e-6 7 #define ll long long 8 ll a[MAXN]={0}; 9 ll Q,t,x,cnt; 10 double f(ll x)//f(x)就是选序列前x项和最大项得到的子序列的max-mean的值 11 { 12 double ave; 13 ave=double(a[x]+a[cnt]-a[cnt-1])/(x+1); 14 return double(a[cnt]-a[cnt-1])-ave; 15 } 16 double sf(int l,int r) 17 { 18 if(l>r)return 0; 19 while(l+1<r) 20 { 21 //cout<<"ok"; 22 int mid=(r+l)/2; 23 if(f(mid)>f(mid-1))l=mid;//根据f(x)随x的增大先增后减 24 else r=mid; 25 } 26 return f(l); 27 } 28 int main() 29 { 30 cnt=0; 31 cin>>Q; 32 for(int i=0;i<Q;i++) 33 { 34 cin>>t; 35 if(t==1) 36 { 37 cin>>x; 38 cnt++;//cnt记录当前输入的数的个数 39 a[cnt]=a[cnt-1]+x; 40 } 41 if(t==2) 42 { 43 //cout<<a[cnt]<<" "; 44 double flag = sf(1,cnt); 45 printf("%.10lf\n",flag);//10个零,第一次数了9个零把我wa了/(ㄒoㄒ)/~~ 46 } 47 } 48 }