【noip2010】引水入城

题解:

先一遍dfs看是否合法

若合法 则从上面任意一点到达下面的点一定是连续的 拓扑求出上面每点到下面的点的区间

把所有区间按头排序 贪心解决最少几个区间能覆盖全部区域之

 

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <queue>
 4 using namespace std;
 5 const int N=501;
 6 struct info{
 7     int x,y;
 8     info(const int a=0,const int b=0):
 9         x(a),y(b){}
10 }map[N][N],qj[N],move[4]={info(1,0),info(-1,0),info(0,1),info(0,-1)};
11 queue <info> que;
12 int n,m,h[N][N],bo[N][N],bein[N][N],ans;
13 bool check(info x,info y){ return x.x+y.x>0 && x.y+y.y>0 && x.x+y.x<=n && x.y+y.y<=m; }
14 inline bool cmp(info a,info b){ return a.x<b.x; }
15 void search(info now){
16     que.push(now);
17     bo[now.x][now.y]=1;
18     while (!que.empty()){
19         now=que.front();
20         que.pop();
21         for (int i=0;i<4;i++)
22         if (check(now,move[i]))
23         if (!bo[now.x+move[i].x][now.y+move[i].y] && h[now.x][now.y]>h[now.x+move[i].x][now.y+move[i].y]){
24             info ne=info(now.x+move[i].x,now.y+move[i].y);
25             bo[ne.x][ne.y]=1;
26             que.push(ne);
27         }
28     }
29 }
30 bool checkbo(){
31     for (int i=1;i<=m;i++)
32     if (!bo[1][i]) search(info(1,i));
33     for (int i=1;i<=m;i++)
34     if (!bo[n][i]) ++ans;
35     return ans;
36 }
37 void makebein(){
38     for (int i=1;i<=n;i++)
39     for (int j=1;j<=m;j++)
40     for (int k=0;k<4;k++)
41     if (check(info(i,j),move[k]))
42     if (h[i][j]<h[i+move[k].x][j+move[k].y]) ++bein[i+move[k].x][j+move[k].y];
43 }
44 int max(int x,int y){
45     if (!x) return y;
46     if (!y) return x;
47     return x>y ? x : y;
48 }
49 int min(int x,int y){
50     if (!x) return y;
51     if (!y) return x;
52     return x<y ? x : y;
53 }
54 void makemap(){
55     for (int j=1;j<=m;j++) map[n][j]=info(j,j);
56     for (int i=1;i<=n;i++)
57     for (int j=1;j<=m;j++)
58     if (!bein[i][j]) que.push(info(i,j));
59     while (!que.empty()){
60         info now=que.front();
61         que.pop();
62         for (int i=0;i<4;i++)
63         if (check(now,move[i]))
64         if (h[now.x][now.y]<h[now.x+move[i].x][now.y+move[i].y]){
65             info ne=info(now.x+move[i].x,now.y+move[i].y);
66             map[ne.x][ne.y].x=min(map[ne.x][ne.y].x,map[now.x][now.y].x);
67             map[ne.x][ne.y].y=max(map[ne.x][ne.y].y,map[now.x][now.y].y);
68             if (!--bein[ne.x][ne.y]) que.push(ne);
69         }
70     }
71 }
72 void makeqj(){
73     makemap();
74     for (int i=1;i<=m;i++) qj[i]=map[1][i];
75 }
76 int getans(){
77     sort(qj+1,qj+m+1,cmp);
78     int res=0;
79     for (int i=1,j=1;i<=m && j<=m;){
80         ++res;
81         int x=0;
82         for (;qj[i].x<=j && i<=m;i++)
83         if (x<qj[i].y) x=qj[i].y;
84         j=x+1;
85     }
86     return res;
87 }
88 int main(){
89     scanf("%d%d",&n,&m);
90     for (int i=1;i<=n;i++)
91     for (int j=1;j<=m;j++) scanf("%d",&h[i][j]);
92     if (checkbo()){
93         printf("0\n%d",ans);
94         return 0;
95     }
96     makebein();
97     makeqj();
98     printf("1\n%d",getans());
99 }
View Code

 

转载于:https://www.cnblogs.com/g-word/p/3383412.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值