[BFS+贪心]【NOIP2010T4】引水入城 题解

(传送门)

解题报告

蒟蒻A水题中……

这道题首先将所有第一行往下扩展,看最后一行能否全部传到来判断无解。

如果有解,那么可以证明,每个第一行的节点所能传到的最后一行节点一定是一个区间。

然后就是一个最少线段覆盖问题了。蒟蒻都忘了板子……

复杂度:
时间: O(nm)
空间: O(nm)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int flg[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
int n,m,k,mp[505][505],ans;
bool vs[505][505];
struct data{
    int x,y;
    data (int x=0,int y=0):x(x),y(y){}
    bool operator < (const data b)const{
        return x<b.x;
    }
}que[250005],b[505];
inline char nc(){
    static char buf[100000],*pa=buf,*pb=buf;
    return pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++;
}
inline void readi(int &x){
    x=0; char ch=nc();
    while ('0'>ch||ch>'9') ch=nc();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
bool _check(int x,int y,int xx,int yy){
    if (x<1||x>n||y<1||y>m) return 0;
    if (mp[x][y]>=mp[xx][yy]) return 0;
    if (vs[x][y]) return 0;
    return 1;
}
void _bfsa(){
    memset(vs,0,sizeof(vs)); int hed=0,til=0;
    for (int i=1;i<=m;i++) {que[++til]=data(1,i); vs[1][i]=1;}
    while (hed!=til){
        int x=que[++hed].x,y=que[hed].y;
        for (int i=0;i<4;i++)
            if (_check(x+flg[i][0],y+flg[i][1],x,y)){
                int tx=x+flg[i][0],ty=y+flg[i][1];
                que[++til]=data(tx,ty); vs[tx][ty]=1;
            }
    }
}
void _bfsb(int sy){
    memset(vs,0,sizeof(vs));
    int hed=0,til=1; que[1]=data(1,sy); vs[1][sy]=1;
    while (hed!=til){
        int x=que[++hed].x,y=que[hed].y;
        for (int i=0;i<4;i++)
            if (_check(x+flg[i][0],y+flg[i][1],x,y)){
                int tx=x+flg[i][0],ty=y+flg[i][1];
                que[++til]=data(tx,ty); vs[tx][ty]=1;
            }
    }
    int i,L=0,R;
    for (i=1;i<=m+1;i++) if (vs[n][i]){L=i; break;}
    if (!L) return;
    for (;i<=m+1;i++) if (!vs[n][i]){R=i-1;break;}
    b[++k]=data(L,R);
}
int main() 
{
    freopen("flow.in","r",stdin);
    freopen("flow.out","w",stdout);
    readi(n); readi(m); k=ans=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) readi(mp[i][j]);
    _bfsa();
    for (int j=1;j<=m;j++) ans+=vs[n][j]^1;
    if (ans) {printf("0\n%d",ans); return 0;}
    for (int j=1;j<=m;j++) _bfsb(j);
    sort(b+1,b+k+1); ans=0;
    for (int i=1,lst=1;lst<=m&&i<=k;){
        int t=0; for (;b[i].x<=lst&&i<=k;i++) t=max(t,b[i].y);
        lst=t+1; ans++;
    }
    printf("1\n%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/78450191