本题是dp。
f [ i ] [ j ] 是表示:差为 j 时, 到第 i 个骨牌需要的步数,初始化为无穷大;
实质是一个背包问题,因为有负数下标,因此多加一个mod (偷懒) 把数组整体右移。
- Q1:dp会不会反了?
- 其实就是个逆向思维,用脑想一下 (其实也不用脑的) j是由 j-dis(个体差值) 得来的,j-dis实际上就是加上 dis 所以根本没有翻转;
- Q2:ans>=1000 break?
- 看题目!看题目!看题目!最小差值,关键就是 j+mod 的含义,就是从小差值开始,所以只要有一个不是无穷大,就是答案了。
- 对了,其实不用一万的,只是我在作死。
巧妙的题目,无脑的我……
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 #define mid ((l+r)>>1) 8 #define maxn 150 9 #define mod 10000 10 #define reg register 11 #define ll long long 12 #define ull unsigned long long 13 #define inf 0x3f3f3f3f 14 #define rep(a,b,c) for(reg int a=b;a<=c;a++) 15 #define Rep(a,b,c) for(reg int a=b;a<c;a++) 16 #define down(a,b,c) for (reg int a=b;a>=c;a--) 17 #define Down(a,b,c) for (reg int a=b;a>c;a--) 18 19 //struct yl{ 20 // int beg,sto,til; 21 //}s[maxn]; 22 int f[1010][20010]; 23 int up[1005],down[1005]; 24 25 inline int read() 26 { 27 char ch=getchar(); 28 int k=0,sign=1; 29 while (ch<'0' || ch>'9') { 30 if (ch=='-') sign=-1; 31 ch=getchar(); 32 } 33 while (ch>='0'&&ch<='9') k=k*10+(ch^48),ch=getchar(); 34 return k*sign; 35 } 36 //bool cmp(yl a,yl b) {return a.beg>b.beg;} 37 //int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);} 38 39 //void P() 40 //{ 41 // rep(i,1,n) 42 // { 43 // rep(j,1,n) 44 // { 45 // printf("%10d ",f1[i][j]); 46 // } 47 // putchar(10); 48 // } 49 //} 50 int main() 51 { 52 // freopen("qnm.in","r",stdin); 53 // freopen("cnm.out","w",stdout); 54 int n=read(); 55 rep(i,1,n) 56 { 57 up[i]=read(); 58 down[i]=read(); 59 } 60 memset(f,0x6f,sizeof(f)); 61 f[0][mod]=0; 62 rep(i,1,n) rep(j,-10000,10000) 63 { 64 int dis=up[i]-down[i]; 65 f[i][j+10000]=min(f[i-1][j+mod-dis],f[i-1][j+mod+dis]+1); 66 } 67 int ans=f[n][mod]; 68 rep(i,1,mod) 69 { 70 ans=min(ans,f[n][i+mod]); 71 if (ans<=1000) 72 { 73 printf("%d\n",ans); 74 break; 75 } 76 } 77 return 0; 78 }
- 代码C++,1.46KB
- 提交时间2018-02-08 23:53:41
- 耗时/内存864ms, 79277KB
2018-02-09 00:44:33