https://www.codechef.com/problems/LEMOUSE
题意:
有一个n *m的网格。有一头大象,初始时在(1,1),要移动到(n,m),每
次只能向右或者向下走。有些格子中有老鼠,如果大象所在的格子和某个有老
鼠的格子的曼哈顿距离$e$1,大象就会被那只老鼠吓到。
求一条移动路径,使得吓到过大象的老鼠数量最少。n;m $le$100。
开始刷济南集训hzc的课件啦!
最简单的一道$DP$
一只老鼠只会吓大象一次$f[i][j][0/1]$记录从左还是上走来的,转移时讨论一下就行了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N=105,INF=1e9+5; double eps=1e-4; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int m,n,a[N][N],s[N][N]; char str[N]; int f[N][N][2]; void dp(){ f[1][1][0]=f[1][1][1]=s[1][1]; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++){ if(i==1&&j==1) continue; if(j-1!=0){ int t1=INF,t2=INF; if(j-2!=0||i==1) t1=f[i][j-1][0]; if(i-1!=0) t2=f[i][j-1][1]-a[i-1][j]; f[i][j][0]=min(t1,t2)+s[i][j]-a[i][j-1]-a[i][j]; } if(i-1!=0){ int t1=INF,t2=INF; if(i-2!=0||j==1) t1=f[i-1][j][1]; if(j-1!=0) t2=f[i-1][j][0]-a[i][j-1]; f[i][j][1]=min(t1,t2)+s[i][j]-a[i-1][j]-a[i][j]; } } //for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("f %d %d %d %d ",i,j,f[i][j][0],f[i][j][1]); //for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("%d%c",f[i][j][0],j==n?' ':' ');puts(""); //for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("%d%c",f[i][j][1],j==n?' ':' ');puts(""); printf("%d ",min(f[m][n][0],f[m][n][1])); } int main(){ freopen("in","r",stdin); int T=read(); while(T--){ m=read();n=read(); memset(s,0,sizeof(s)); for(int i=1;i<=m;i++){ scanf("%s",str+1); for(int j=1;j<=n;j++){ a[i][j]=str[j]-'0'; if(a[i][j]) s[i][j]++,s[i-1][j]++,s[i+1][j]++,s[i][j-1]++,s[i][j+1]++; } } //for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("%d%c",a[i][j],j==n?' ':' ');puts(""); //for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) printf("%d%c",s[i][j],j==n?' ':' ');puts(""); dp(); } }