阵列弱点
【题目背景】
最后的会战:水滴对阵 n*m 架战舰。
悲剧的阵列喂饱了水滴,上百架战舰就是一串挂炮。
【题目描述】
抽象会战前的阵列为一个n*m的矩阵。每一个元素对应一个战舰。每一个战舰有一个
特征值。水滴希望找到一条特征值先下降后上升(可以只变大或者只变小)的路径(即一
个元素序列,满足相邻两个元素在阵列中的曼哈顿距离为1,或者说相邻两个元素上下左右
四连通,且每一个元素在路径中最多出现一次)。为了取得最好的爆炸效果,希望你能求
出最长的路径及其方案。
【输入】(weakness.in)
第一行两个数 n,m 意义同上
接下来 n 行,每行 m 个数,用空格分开,描述了整个阵列的特征值。
【输出】(weakness.out)
第一行只有一个数 s,表示最长满足要求的路径的元素个数
接下来 s 行,每一行两个数(用空格分开)x y。第 i+1 行表示第 i 个元素的坐标(行列
表示)
【样例输入】
4 4
5 14 3 4
1 6 9 8
10 15 2 12
13 11 7 16
【样例输出】
6
4 4
3 4
2 4
1 4
1 3
2 3
【数据规模】
n,m<=60
阵列中的任意两个元素不相等,且在 32 位长整型范围内
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=20010,M=2000010,K=62,INF=1000000000;
int cnt,fir[N],to[M],nxt[M],cap[M],val[M];
void addedge(int a,int b,int c,int v){
nxt[++cnt]=fir[a];to[fir[a]=cnt]=b;cap[cnt]=c;val[cnt]=v;
nxt[++cnt]=fir[b];to[fir[b]=cnt]=a;cap[cnt]=0;val[cnt]=-v;
}
int q[M],front,back;
bool vis[N];
int dis[N],path[N];
int BFS(int S,int T){
q[front=back]=S;vis[S]=true;
for(int i=1;i<=T;i++)dis[i]=-INF;
while(front<=back){
int x=q[front++];vis[x]=false;
for(int i=fir[x];i;i=nxt[i])
if(cap[i]&&dis[to[i]]<dis[x]+val[i]){
dis[to[i]]=dis[x]+val[i];
if(!vis[to[i]])q[++back]=to[i];
vis[to[i]]=true;path[to[i]]=i;
}
}
return dis[T];
}
void Aug(int S,int T){
int p=T;
while(p!=S){
cap[path[p]]-=1;
cap[path[p]^1]+=1;
p=to[path[p]^1];
}
}
int McMf(int S,int T){
int ret=0,d;
while((d=BFS(S,T))!=-INF){
ret+=d;Aug(S,T);
}
return ret;
}
int a[K][K],st[N],top;
int n,m,ans,ansx,ansy,idx,S,T;
int id[K][K],id2[K][K],w[K][K];
void Init(){
memset(fir,0,sizeof(fir));
S=0;T=2*n*m+1;cnt=1;
}
int Solve(int x,int y){
Init();
addedge(S,id2[x][y],2,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
addedge(id[i][j],id2[i][j],1,0);
addedge(id2[i][j],T,1,0);
if(id[i+1][j]&&a[i][j]<a[i+1][j])addedge(id2[i][j],id[i+1][j],1,1);
if(id[i-1][j]&&a[i][j]<a[i-1][j])addedge(id2[i][j],id[i-1][j],1,1);
if(id[i][j+1]&&a[i][j]<a[i][j+1])addedge(id2[i][j],id[i][j+1],1,1);
if(id[i][j-1]&&a[i][j]<a[i][j-1])addedge(id2[i][j],id[i][j-1],1,1);
}
return McMf(S,T)+1;
}
void DFS(int x){
st[++top]=x;
for(int i=fir[x+n*m];i;i=nxt[i])
if(to[i]!=T&&cap[i]==0)DFS(to[i]);
}
int main(){
freopen("weakness.in","r",stdin);
freopen("weakness.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
id[i][j]=++idx;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
id2[i][j]=++idx;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++){
int tmp=Solve(x,y);
if(tmp>ans){
ans=tmp;
ansx=x;
ansy=y;
}
}
Solve(ansx,ansy);
printf("%d\n",ans);
int flag=0,pos=id2[ansx][ansy];
for(int i=fir[pos];i;i=nxt[i])
if(cap[i]==0){
if(to[i]==id[ansx][ansy])continue;
if(to[i]==S||to[i]==T)continue;
top=0;DFS(to[i]);
if(flag){
printf("%d %d\n",ansx,ansy);
for(int j=1;j<=top;j++){
int x=st[j];
printf("%d %d\n",(x-1)/m+1,(x-1)%m+1);
}
break;
}
else{
flag=1;
while(top){
int x=st[top--];
printf("%d %d\n",(x-1)/m+1,(x-1)%m+1);
}
}
}
return 0;
}