NOIP模拟题——集结蚂蚁
【题目描述】
雄心勃勃的企业家达伦·克劳斯发现了皮姆博士有关缩小原子间距离的公式并
研发出新一代微型“黄蜂战士”,皮姆博士担忧武器会引发不可挽回的后果,于是
找到斯科特并使他成为了新一代“蚁人”。正逢克劳斯与外商交易黄蜂战衣的那天,
斯科特受命前往摧毁黄蜂战衣并销毁数据,然而一个人的力量是渺小的,斯科特需
要走入一个巨大的蚁穴去召唤蚂蚁与他共同作战。
蚁穴是一个巨大复杂的地带,由n 行m 列组成,每个偶数行存在至少一个蚂蚁
聚集地,同一行的不同蚂蚁聚集地以一堵墙隔开,每个蚂蚁聚集地的大小为Si;
每个奇数行存在连接相邻偶数行中蚂蚁聚集地的路径,一个蚂蚁聚集地可能有多条
路径可以到达。
蚁人可从蚁穴的第一行任何一路口出发,由于时间紧迫,蚁人只能向下一行走,
在这种情况下,蚁人希望你能告诉他如何使经过的蚂蚁聚集地大小之和最大,从而
召唤最多的蚂蚁。
【输入】
第1 行包含两个用空格隔开的整数n,m,意义见描述。
第2 到n+1 行,每行m 个字符(无间隔)且仅存在0 和1:同一偶数行中连
续x 个0 组成一个大小为x 的蚂蚁聚集地,1 为墙体;奇数行中0 表示蚁人可以从
此处通过。
【输出】
对于每组数据输出一个整数,表示经过路径中最大聚集地之和(不包含聚集
地之间的路径)。若蚁人无法到达最后一行则请输出“-1”。
4
【输入样例】
10 10
1111101111
1100001011
1101111111
1100000101
1110110111
1000110001
1101111011
1101000011
1101011111
1101010001
【输出样例】
17
【样例解释】
【数据规模】
对于20%的数据,n≤20,m≤20
对于50%的数据,n≤20,m≤100
对于100%的数据,n≤5000,m≤2000,保证n 是一个偶数,路径的数量不多于1×106
在输入的时候存每一行连续0的个数,若其中有一个0上面也是0(即是可以走的),便更新它的权值,到最后或碰到1时,看上一个可行点
是否可以更改权值。
后面直接就每一行每一行搜索了,由于存的是区间,每个区间只扫一次,所以最大时间复杂度O(mn)。
好像用建图SPFA做也可以。
1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 using namespace std;
5 const int maxn=5005;
6 const int maxm=2005;
7 int map[maxn][maxm];//1000w
8 int pos[maxn][maxm>>1];//500w(不连在一起的位置)
9 int f[maxn][maxm];//1000w
10 int w[maxn][maxm>>1];//500w
11 int n,m;
12 int main()
13 {
14 freopen("ant.in","r",stdin);
15 freopen("ant.out","w",stdout);
16 scanf("%d%d",&n,&m);
17 int t=0;int pre=1;bool pd=false;
18 for(int i=1;i<=n;i++)
19 {
20 t=0;
21 for(int j=1;j<=m;j++)
22 {
23 char c=getchar();
24 while(c!='0'&&c!='1')c=getchar();
25 map[i][j]=c-'0';
26
27
28 if(i==1)continue;
29
30 if(map[i][j]==0)
31 t++;
32 if(map[i][j]==1&&pd==false){t=0;continue;}
33 if(map[i][j]==1&&pos[i][pos[i][0]]+t>=j&&pd==true)
34 {
35 w[i][pos[i][0]]=t;
36 t=0;pd=false;
37 }
38 if(map[i][j]==0&&map[i-1][j]==0)//可以标记
39 {
40 pd=true;
41 if(pos[i][0]==0)
42 {
43 pos[i][++pos[i][0]]=j;
44 w[i][pos[i][0]]=t;
45 }
46 else if(pos[i][pos[i][0]]+t-1>=j)
47 {
48 pos[i][pos[i][0]]=j;
49 }
50 else
51 pos[i][++pos[i][0]]=j;
52 }
53 if(pd==true&&j==m&&map[i][j]==0)
54 {
55 w[i][pos[i][0]]=t;
56 }
57 }
58 }
59 for(int i=1;i<=m;i++)
60 f[1][i]=-1;
61 for(int i=2;i<=n;i++)
62 for(int j=1;j<=pos[i][0];j++)
63 {
64 if(i%2==0)//聚集地
65 {
66 if(i!=2)
67 {
68 int k=pos[i][j];int k2=pos[i][j];
69 int v=w[i][j];int er=0;
70 while(map[i][k]==0)
71 {
72 if(k==0)break;
73 er=max(er,f[i-1][k]);
74 k--;
75 }k++;
76 while(map[i][k2]==0)
77 {
78 if(k2==m+1)break;
79 er=max(er,f[i-1][k]);
80 k2++;
81 }k2--;
82 if(er==0)continue;
83 else
84 {
85 for(int as=k;as<=k2;as++)
86 f[i][as]=er+v;
87 }
88 }
89 else
90 {
91 int k=pos[i][j];int k2=pos[i][j];
92 int v=w[i][j];
93 while(map[i][k]==0)
94 {
95 if(k==0)break;
96 k--;
97 }k++;
98 while(map[i][k2]==0)
99 {
100 if(k2==m+1)break;
101 k2++;
102 }k2--;
103 for(int as=k;as<=k2;as++)
104 f[i][as]=v;
105 }
106 }
107 else
108 {
109 int k=pos[i][j];int k2=pos[i][j];
110 int v=f[i-1][pos[i][j]];
111 while(map[i][k]==0)
112 {
113 if(k==0)break;
114 v=max(f[i-1][k],v);
115 k--;
116 }k++;
117 while(map[i][k2]==0)
118 {
119 if(k2==m+1)break;
120 v=max(f[i-1][k2],v);
121 k2++;
122 }k2--;
123 if(v==0)continue;
124 else
125 {
126 for(int as=k;as<=k2;as++)
127 f[i][as]=v;
128 }
129 }
130 }
131 int ans=0;
132 for(int i=1;i<=m;i++)
133 if(f[n][i]>ans)ans=f[n][i];
134 if(ans==0)
135 printf("-1");
136 else
137 printf("%d",ans);
138 return 0;
139 }