洛谷1514 引水入域 dp+記憶化搜索

題目連接:https://www.luogu.com.cn/problem/P1514ios

題意大體是:給定一個(n,m)的數值矩陣,能夠在第一行建造水庫,若是一個格子周圍的某格子值小於它,那水就能夠流到它周圍的那個格子,問須要在第一行建造多少水庫使得最後一行可以被徹底覆蓋,若是不能徹底覆蓋就求出不能覆蓋的格子的數量。c++

主要思路就是在第一行每一個點出發的水能到達第n行的區間能夠得到(能夠用反證法證實每一個點出發的水若是能到達第n行那麼它的覆蓋區間必定是連續的),若是可以徹底覆蓋第n行則用最小區間數覆蓋能夠求出最少須要多少個點能夠覆蓋第n行,ui

代碼以下:spa

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned int ui;
 4 typedef long long ll;
 5 typedef unsigned long long ull;
 6 #define pf printf
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 #define prime1 1e9+7
 9 #define prime2 1e9+9
10 #define scand(x) scanf("%llf",&x) 
11 #define f(i,a,b) for(int i=a;i<=b;i++)
12 #define scan(a) scanf("%d",&a)
13 #define dbg(args) cout<<#args<<":"<<args<<endl;
14 #define pb(i) push_back(i)
15 #define ppb(x) pop_back(x)
16 #define inf 0x3f3f3f3f
17 #define maxn 1005
18 int n,m,t,a[maxn][maxn],l[maxn][maxn],r[maxn][maxn],vis[maxn][maxn];
19 //l[i][j]從(i,j)位置出發的水最多能覆蓋到最後一行的左端的位置,
20 //r[i][j]從(i,j)位置出發的水最多能覆蓋到最後一行的最右端的位置 
21 int dir[][2]={{1,0},{0,-1},{-1,0},{0,1}};
22 void dfs(int x,int y)
23 {
24     vis[x][y]=true;//代表(x,y)位置的l,r信息都被處理過 
25     int xx,yy;
26     f(i,0,3)
27     {
28         xx=x+dir[i][0];
29         yy=y+dir[i][1];
30         if(xx<=0||xx>n||yy<=0||yy>m)continue;
31         if(a[xx][yy]>=a[x][y])continue;
32         if(!vis[xx][yy])
33         {
34             dfs(xx,yy);
35         }
36         l[x][y]=min(l[x][y],l[xx][yy]);
37         r[x][y]=max(r[x][y],r[xx][yy]);
38     }
39 }
40 int main()
41 {
42     //freopen("input.txt","r",stdin);
43     //freopen("output.txt","w",stdout);
44     std::ios::sync_with_stdio(false);
45     scan(n);
46     scan(m);
47     f(i,1,n)
48         f(j,1,m)
49         {
50             scan(a[i][j]);
51         }
52         mem(l,inf);
53         mem(r,-inf);
54         f(1,1,m)
55         {
56             l[n][i]=r[n][i]=i;//最下面一層,初始狀況區間只覆蓋本身 
57         }
58         f(i,1,m)
59         {
60             if(!vis[1][i])
61             dfs(1,i);
62         }
63         bool  flag=true;
64         int cnt=0;
65         f(i,1,m)
66         {
67             if(!vis[n][i])
68             {
69                 flag=false;
70                 cnt++;
71             }
72         }
73         if(!flag)
74         {
75             pf("0\n%d",cnt);//有多少個點沒法覆蓋 
76         }
77         else 
78         {
79             int num=0;
80             int left=1,maxr=0;//最小區間數覆蓋 
81             while(left<=m)
82             {
83                 maxr=0;
84                 f(i,1,m)
85                 {
86                     if(l[1][i]<=left)//找到覆蓋left點的區間右端值的最大值 
87                     maxr=max(maxr,r[1][i]);
88                 }
89                 left=maxr+1;
90                 num++;
91              } 
92             pf("1\n%d\n",num);
93         /*    f(i,1,m)
94             {
95                 pf("%d %d\n",l[1][i],r[1][i]);
96             }*/
97         }
98         return 0;
99  } 
相關文章
相關標籤/搜索