NOIP2010 引水入城 解题报告(bfs+dp)

在线评测:

http://codevs.cn/problem/1066/


整体思路:

先将沿河的所有城市加入队列,进行bfs,然后看能不能做到每个城市都有水,如果不能则直接输出即可,若能操作顺序如下:

以每一个近水点为原点搜一下,求出每个可建蓄水池位置建造蓄水池后的最大影响范围(记得vis数组要重置)

这里可以会怀疑如果一个原点所能覆盖的城市不是连续的该怎么办,我们可以想一下,如果一个点分割了一个原点所能覆盖的几个城市(在同一横上),那么我们可以知道这个点一定高于两侧的点,而这个点无法被水覆盖可以抽象成他上面的点也无法被水覆盖,也高于两侧的点,如次递归下去,我们会发现,根本不存在一个原点在靠近沙漠一横排的覆盖区域被分割的情况。

ok!现在我们求出了每个点所能到达的一个区域,此时我们可以将问题进一步抽象为在靠近沙漠的一排上,进行线段覆盖,用最少的线段覆盖满所有的区域,于是我们可以进行dp

1
2
3
4
5
f[0]=0;
     for  (int i = 1;i <= m;i++)
         for  (int j = jl[i].s;j <= jl[i].t;j++)
             if  (f[j]>f[jl[i].s - 1] +1 || !f[j])
                 f[j] = f[jl[i].s - 1] + 1;
f【i】代表覆盖至i号格子所需的最少线段数

最后输出f【m】即可


失误之处:

1、bfs的时候没有将第一个点的vis打上标志,导致无法判断城市为1*n的情况

2、修改了一个bfs的以上问题时另外一个没有修改,,,,

3、什么bfs的时候没pop队列了之列的,,,,

4、开始的时候,下面if的else直接就else了,然后就悲催,,,不要无脑else,要仔细分析!!

1
2
3
4
5
6
7
8
9
for  (int i = 1;i <= m;i++)
     {
         if  (vis[n][i] && pd)
         {
             jl[x].s = i;
             jl[x].t = i;
             pd =  false ;
         } else  if  (vis[n][i]) jl[x].t = i;
     }

体会心得:

1、仔细仔细!!!

2、常用的算法还是应该常写写,,到时候丢三落四


AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
struct lx
{
     int hg,shu;   
};
struct xd
{
     int s,t;
};
queue dl;
int n,m,sz[600][600],h[5] = {0,1,-1,0,0},s[5] = {0,0,0,1,-1};
bool vis[600][600];
xd jl[510];
int pd()
{
     int ftot = 0;
     for  (int i = 1;i <= m;i++)
         if  (!vis[n][i]) 
         {
             ftot++;
         }
     return  ftot;  
}
void bfs(int x)
{
     memset(vis,0,sizeof(vis));
     vis[1][x] =  true ;
     lx btp;
     btp.hg = 1;
     btp.shu = x;
     dl.push(btp);
     while  (!dl.empty())
     {
         lx ftp = dl.front();
         dl.pop();
         int hz = ftp.hg;
         int lz = ftp.shu;
         for  (int i = 1;i <= 4;i++)
         {
             if  (sz[hz+h[i]][lz+s[i]] < sz[hz][lz])
             {
                 if  (!vis[hz+h[i]][lz+s[i]]) 
                 {
                     lx ftp;
                     ftp.hg = hz+h[i];
                     ftp.shu = lz+s[i];
                     dl.push(ftp);
                 }
                 vis[hz+h[i]][lz+s[i]] =  true ;
            
         }
     }
     bool pd =  true ;
     for  (int i = 1;i <= m;i++)
     {
         if  (vis[n][i] && pd)
         {
             jl[x].s = i;
             jl[x].t = i;
             pd =  false ;
         } else  if  (vis[n][i]) jl[x].t = i;
     }
}
bool bj(xd a,xd b)
{
     if  (a.s < b.s)  return  true ;
     if  (a.s > b.s)  return  false ;
     if  (a.t > b.t)  return  true ;
     return  false ;
}
int main()
{
     scanf( "%d%d" ,&n,&m);
     memset(sz,0x1f,sizeof(sz));
     for  (int i = 1;i <= n;i++)
     {
         for  (int j = 1;j <= m;j++)
         {
             scanf( "%d" ,&sz[i][j]);
         }
     }
     for  (int i = 1;i <= m;i++)
     {
         lx tp;
         tp.hg = 1;
         tp.shu = i;
         dl.push(tp);
         vis[1][i] =  true ;
     }
     while  (!dl.empty())
     {
         lx tp = dl.front();
         dl.pop();
         int hz = tp.hg;
         int lz = tp.shu;
         for  (int i = 1;i <= 4;i++)
         {
             if  (sz[hz+h[i]][lz+s[i]] < sz[hz][lz])
             {
                 if  (!vis[hz+h[i]][lz+s[i]]) 
                 {
                     lx ftp;
                     ftp.hg = hz+h[i];
                     ftp.shu = lz+s[i];
                     dl.push(ftp);
                 }
                 vis[hz+h[i]][lz+s[i]] =  true ;
            
         }
     }
     if  (int ftp = pd())
     {
         printf( "0\n%d\n" ,ftp);
         return  0;
     }
     for  (int i = 1;i <= m;i++)
     {
         bfs(i);
     }
 
     int zj = 0,tt = 0;
 
     int f[1000];
     f[0]=0;
     for  (int i = 1;i <= m;i++)
         for  (int j = jl[i].s;j <= jl[i].t;j++)
             if  (f[j]>f[jl[i].s - 1] +1 || !f[j])
                 f[j] = f[jl[i].s - 1] + 1;
     printf( "1\n%d" ,f[m]);
     return  0;
}

你可能感兴趣的:(NOIP2010,NOIP模拟,DP+BFS)