【纪中受难记】——Day11:傻逼题遇上傻逼人

事先声明,对题目并无恶意中伤,题目承受的痛苦由傻逼本人(我)来承担。

55/50/45/0


Description


一天, 一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安
全的。
森林的地图由R行C列组成,空白区域用点“.”表示,洪水的区域用“*”表示,而
岩石用“X”表示,另画家的住所用“D”表示,画家用“S”表示。
有以下几点需要说明:
1、 每一分钟画家能向四个方向移动一格(上、下、左、右)
2、 每一分钟洪水能蔓延到四个方向的相邻格子(空白区域)
3、 洪水和画家都不能通过岩石区域
4、 画家不能通过洪水区域(同时也不行,即画家不能移到某个格子,该格子在画家达到的同时被洪水蔓延到了,这也是不允许的)
5、 洪水蔓不到画家的住所。
给你森林的地图,编写程序输出最少需要花费多长时间才能从开始的位置赶回家中。
 

Input

输入第一行包含两个整数R和C(R,C<=50)。
接下来R行每行包含C个字符(“.”、“*”、“X”、“D”或“S”)。地图保证只有一个“D”和一个“S”。

Output

输出画家最快安全到达住所所需的时间,如果画家不可能安全回家则输出“KAKTUS”。
 

Sample Input

输入1:
3 3 
D.* 
... 
.S. 

输入2:
3 3 
D.* 
...
..S

输入3:
3 6 
D...*. 
.X.X.. 
....S. 

Sample Output

输出1:
3

输出2:
KAKTUS 

输出3:
6

简单的广搜,居然没注意有很多洪水,反正各开一个队列,先洪水再人即可。

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 using namespace std;
 4 #define f(i,a,b) for(int i=a;i<=b;i++)
 5 const int N=60;
 6 const int T=120;
 7 int r,c;
 8 struct pos{
 9     int x,y,t;
10 }D,S,F;
11 int ma[N][N],t,x[5]={1,0,-1,0},y[5]={0,1,0,-1},vis[N][N];
12 queue<pos> p;
13 queue<pos> q;
14 char a;
15 void out(pos a){
16     cout<<"pos:"<<a.x<<" "<<a.y<<endl;
17     for(int i=1;i<=r;i++){
18         for(int j=1;j<=c;j++){
19             cout<<ma[i][j]<<" ";
20         }
21             cout<<endl;
22     }
23 }
24 int main(){
25     while(!p.empty()) p.pop();
26     while(!q.empty()) q.pop();
27 //    freopen("data1.in","r",stdin);
28     scanf("%d%d",&r,&c);
29     f(i,1,r){
30         f(j,1,c){
31             scanf("%1s",&a);
32             if(a=='D'){
33                 D.x=i,D.y=j;
34                 ma[i][j]=2;
35             }
36             else if(a=='S'){
37                 S.x=i,S.y=j,S.t=1;
38                 ma[i][j]=1;
39             }
40             else if(a=='*'){
41                 p.push((pos){i,j,1});
42                 ma[i][j]=3;
43             }
44             else if(a=='X'){
45                 ma[i][j]=4;
46             }
47             else;
48         }
49     }
50     q.push(S);
51     while(1){
52         t++;
53         pos nowf=p.front();
54         while(nowf.t==t){
55             p.pop();
56             f(i,0,3){
57                 if(nowf.x+x[i]<=0||nowf.x+x[i]>r||nowf.y+y[i]<=0||nowf.y+y[i]>c) continue;
58                 if(!ma[nowf.x+x[i]][nowf.y+y[i]]){
59                     ma[nowf.x+x[i]][nowf.y+y[i]]=3;
60                     p.push((pos){nowf.x+x[i],nowf.y+y[i],t+1});
61                 } 
62             }
63             nowf=p.front();
64         }
65         bool flag=0;
66         pos nowd=q.front();
67         while(nowd.t==t){
68 //            out(nowd);
69             q.pop();
70             f(i,0,3){
71                 if(nowd.x+x[i]<=0||nowd.x+x[i]>r||nowd.y+y[i]<=0||nowd.y+y[i]>c) continue;
72                 if(vis[nowd.x+x[i]][nowd.y+y[i]]) continue;
73                 if(!ma[nowd.x+x[i]][nowd.y+y[i]]){
74                     vis[nowd.x+x[i]][nowd.y+y[i]]=1;
75                     q.push((pos){nowd.x+x[i],nowd.y+y[i],t+1});
76                     flag=1;
77                 }
78                 else if(ma[nowd.x+x[i]][nowd.y+y[i]]==2){
79                     printf("%d",t);
80                     return 0;
81                 } 
82             }
83             nowd=q.front();
84         }
85         if(!flag){
86             printf("KAKTUS\n");
87             return 0;
88         }
89     }
90     return 0;
91 }

Description

每个人都知道詹姆斯邦德,著名的007,但很少有人知道很多任务都不是他亲自完成的,而是由他的堂弟们吉米邦德完成(他有很多堂弟),詹姆斯已经厌倦了把一个个任务分配给一个个吉米,他向你求助。
每个月,詹姆斯都会收到一些任务,根据他以前执行任务的经验,他计算出了每个吉米完成每个任务的成功率,要求每个任务必须分配给不同的人去完成,每个人只能完成一个任务。
请你编写程序找到一个分配方案使得所有任务都成功完成的概率。
 

Input

输入第一行包含一个整数N,表示吉米邦德的数量以及任务的数量(正好相等,1<=N<=20)。
接下来N行,每行包含N个0到100之间整数,第i行的第j个数Aij表示吉米邦德i完成任务j成功的概率为Aij%

Output

输出所有任务成功完成最大的概率,结果保留6位小数。
 

Sample Input

输入1:
2 
100 100 
50 50 

输入2:
2 
0 50 
50 0 

输入3:
3 
25 60 100 
13 0 50 
12 70 90 

Sample Output

输出1:
50.000000

输出2:
25.000000

输出3:
9.100000

第一眼看这题,误以为数据是50,就没想到正解(但听说打搜索剪枝有95分),明显是状压DP,设f[i][j]表示第i行状态为j的最大概率(j中有1个1),设s[i][j]表示第i行状态为j的最大概率(j中有i个1),枚举上一行的s[i][j],找出不冲突的状态转移取最大值即可。

后注:

1.你妈的,调了俩小时发现数组开小了。

2.听说这题还能用二分图做,二分图最大匹配的时候,利用对数性质把乘积变成对数的和即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=21;
 4 int n;
 5 double sum[2][1<<N];
 6 int num[1<<N];
 7 int mis[N][N],q;
 8 void ini(){
 9     for(int i=1;i<(1<<n);i++){
10         int t=i;
11         int ans=0;
12         while(t){
13             if(t&1) ans++;
14             t>>=1;
15         }
16         num[i]=ans;
17     }
18     for(int i=1,k=1;i<(1<<n);i<<=1,k++){
19         sum[1][i]=mis[1][k];
20     }
21 }
22 int main(){
23     memset(sum,0,sizeof(sum));
24     memset(mis,0,sizeof(mis));
25     memset(num,0,sizeof(num));//毫无卵用
26 //    freopen("data.in","r",stdin);
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++){
29         for(int j=1;j<=n;j++){
30             scanf("%d",&mis[i][j]);
31         }
32     }
33     ini();
34     for(int i=2;i<=n;i++){
35         q=i%2;
36         for(int k=1,l=1;k<(1<<n);k<<=1,l++){
37             for(int j=1;j<(1<<n);j++){
38                 if(num[j]!=i-1||j&k) continue;
39                 sum[q][j|k]=max(sum[q][j|k],sum[q^1][j]*mis[i][l]/100);
40 //                cout<<sum[q][j|k]<<endl;
41             }
42         }
43     }
44     printf("%.6f",sum[q][(1<<n)-1]);
45     return 0;
46 }

Description

你家刚买了一套新房,想邀请朋友回来庆祝,所以需要一个很大的举行餐桌,餐桌能容纳的人数等于餐桌的周长,你想买一个能容纳最多人的餐桌,餐桌的边必须跟房间的边平行。
给你的房间的设计,计算最多能邀请的客人数。
 

Input

第一行包含两个整数R和C(1<=R,C<=2000),表示房子的长和宽。
接下来R行每行S个字符(中间没有空格),“.”表示空白区域,“X”表示有障碍物,餐桌所占区域必须是空白的。

Output

输出最多能要求的客人数量。
 

Sample Input

输入1:
2 2
..
..

输入2:
4 4 
X.XX 
X..X 
..X. 
..XX 

输入3:
3 3 
X.X 
.X. 
X.X 

Sample Output

输出1:
7

输出2:
9

输出3:
3
 

Data Constraint

 
 

Hint

【数据规模】
50%的数据R,C<=400
70%的数据R,C<=1000
100%的数据,R,C<=2000

想到动态规划,但考试的时候列错了。

正解:设h[i][j]表示点(i,j)向上方扩展的最高位置,l[i][j],r[i][j]分别表示在最高位置向左或者向右能到达的最远位置,用前缀和预处理一下即可。

不知道为啥内存会炸,明明没超过的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2100;
 4 int r,c;
 5 int a[N][N],ans;
 6 int sum[N][N],h[N][N],ll[N][N],rr[N][N];
 7 char t;
 8 int getsum(int x1,int y1,int x2,int y2){
 9     return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
10 }
11 int main(){
12     scanf("%d%d",&r,&c);
13     for(int i=1;i<=r;i++){
14         for(int j=1;j<=c;j++){
15             scanf("%1s",&t);
16             a[i][j]=(t=='.'?1:0);
17             sum[i][j]=sum[i-1][j]+sum[i][j-1]+a[i][j]-sum[i-1][j-1];
18         }
19     }
20 
21     for(int i=1;i<=r;i++){
22         for(int j=1;j<=c;j++){
23             if(!a[i][j]) continue;
24             for(int l=1;i+l<=r;l++){
25                 if(a[i+l][j]) h[i][j]=l;
26                 else break;
27             }
28         }
29     }
30 
31     for(int i=1;i<=r;i++){
32         for(int j=1;j<=c;j++){
33             if(!a[i][j]) continue;
34             for(int l=1;j+l<=c;l++){
35                 if(getsum(i,j,i+h[i][j],j+l)==(h[i][j]+1)*(l+1)) rr[i][j]=l;
36                 else break;
37             }
38         }
39     }
40 
41     for(int i=1;i<=r;i++){
42         for(int j=1;j<=c;j++){
43             if(!a[i][j]) continue;
44             for(int l=1;j-l>0;l++){
45                 if(getsum(i,j-l,h[i][j]+i,j)==(h[i][j]+1)*(l+1)) ll[i][j]=l;
46                 else break;
47             }
48         }
49     }
50     for(int i=1;i<=r;i++){
51         for(int j=1;j<=c;j++){
52             ans=max(ans,(h[i][j]+1+rr[i][j]+ll[i][j]+1)*2);
53         }
54     }
55     printf("%d",ans-1);
56     return 0;
57 }

Description

自行车赛在一个很大的地方举行,有N个镇,用1到N编号,镇与镇之间有M条单行道相连,起点设在镇1,终点设在镇2。
问从起点到终点一共有多少种不同的路线。两条路线只要不使用完全相同的道路就被认为是不同的。
 

Input

第一行两个整数:N和M(1<=N<=10000,1<=M<=100000),表示镇的数量和道路的数量。
接下来M行,每行包含两个不同的整数A和B,表示有一条从镇A到镇B的单行道。
两个镇之间有可能不止一条路连接。

Output

输出不同路线的数量,如果答案超过9位,只需输出最后9位数字。如果有无穷多的路线,输出“inf”。
 

Sample Input

输入1:
6 7 
1 3 
1 4 
3 2 
4 2 
5 6 
6 5 
3 4 

输入2:
6 8 
1 3 
1 4 
3 2 
4 2 
5 6 
6 5 
3 4 
4 3 

输入3:
31 60 
1 3 
1 3 
3 4 
3 4 
4 5 
4 5 
5 6 
5 6 
6 7 
6 7 
… 
… 
… 
28 29 
28 29 
29 30 
29 30 
30 31 
30 31 
31 2 
31 2 

Sample Output

输出1:
3

输出2:
inf

输出3:
073741824 

拓扑排序判环+dp计算答案,标程不写了。


总结:加油上300分就滚去A组玩啊!要不250也行,总之至少A过俩题吧!

猜你喜欢

转载自www.cnblogs.com/Nelson992770019/p/11332657.html
今日推荐