解题报告
蒟蒻A水题中……
这道题首先将所有第一行往下扩展,看最后一行能否全部传到来判断无解。
如果有解,那么可以证明,每个第一行的节点所能传到的最后一行节点一定是一个区间。
然后就是一个最少线段覆盖问题了。蒟蒻都忘了板子……
复杂度:
时间:
空间:
#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;
}