本题是动态规划,胆初看时没有发现,后来才明白
可优化空间到2N不用MN
从后往前推状态的时候要再定一个数组来保存搜有到达的状态,最后再取没有管道的就行了
因为过程类似完全背包,所以要从下往上推点击次数
AC代码
#include<cstdio> #include<iostream> #include<cstring> #define MAX 10002 using namespace std; int x[MAX],y[MAX]; int up[MAX],down[MAX]; int f[MAX],d[MAX]; int n,m,k; int ans,cnt; bool flag; const int INF=0xfffffff; int _min(int a,int b) { return a<b?a:b; } void init() { cin>>n>>m>>k; for(int i=0;i<=n;i++) up[i]=m+1; for(int i=0;i<n;i++) scanf("%d %d",&x[i],&y[i]); for(int i=1;i<=k;i++) {int no; scanf("%d",&no); scanf("%d%d",&down[no],&up[no]); } ans=INF; } int dp() { for(int i=1;i<=m;i++) f[i]=0; for(int i=1;i<=n;i++) { flag=0; fill(d,d+MAX,INF); //点击 for(int j=1;j<=m;j++) { if(j-x[i-1]<up[i-1]&&j-x[i-1]>down[i-1]&&d[j]>f[j-x[i-1]]+1) d[j]=f[j-x[i-1]]+1; if(j-x[i-1]>0&&d[j]>d[j-x[i-1]]+1) d[j]=d[j-x[i-1]]+1; } //如果飞起来撞到顶 for(int j=m-x[i-1]+1;j<=m;j++) { if(j>down[i-1]&&j<up[i-1]) d[m]=_min(f[j]+1,d[m]); d[m]=_min(d[j]+1,d[m]); } //不点击 for(int j=1;j<=m;j++) if(j+y[i-1]>down[i-1]&&j+y[i-1]<up[i-1]&&d[j]>f[j+y[i-1]]) d[j]=f[j+y[i-1]]; for(int j=down[i]+1;j<up[i];j++) if(d[j]<INF)flag=1; if(!flag) { printf("0 %d",cnt); return 0; } if(up[i]<=m)cnt++; memcpy(f,d,sizeof(f)); } for(int i=1;i<m;i++) ans=_min(ans,f[i]); return 1; } int main() { freopen("bird.in","r",stdin); freopen("bird.out","w",stdout); init(); if(dp()) printf("1 %d",ans); return 0; }