BZOJ1930 [Shoi2003]pacman 吃豆豆
dp,首先建出图,f[i][j]表示a吃到了i点,b吃到了j点的最大值,转移的时候转移拓扑序小的那一维,如果i拓扑序小于j,那么转移到f[k][j],否则转移到f[i][k],建出的图边数也要优化,不然会超时。优化的方法是假如i,j连边,那么如果有一条边(i,k),x[k]>x[j]并且y[k]>y[j]那么(i,k)这条边就没有必要存在了。因为先取(i,j)在去(j,k)会比直接取(i,k)要好。
代码
1 #include<cstdio> 2 #include<algorithm> 3 #define N 10010 4 using namespace std; 5 int n,i,j,rd[N],t,w,tot,id[N]; 6 int dp,pre[3000000],p[N],tt[3000000],z[N],ID[N],tmp; 7 int f[2500][2500]; 8 struct g{ 9 int x,y; 10 }a[N]; 11 bool cmp(g a,g b) 12 { 13 if (a.x==b.x) 14 return a.y<b.y; 15 return a.x<b.x; 16 } 17 void link(int x,int y) 18 { 19 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y; 20 } 21 void Dp(int x,int y) 22 { 23 int i; 24 i=p[x]; 25 while (i) 26 { 27 int a=tt[i],b=y; 28 if (id[a]>id[b]) 29 swap(a,b); 30 if (a!=b) 31 f[a][b]=max(f[a][b],f[x][y]+1); 32 else 33 f[a][b]=max(f[a][b],f[x][y]); 34 i=pre[i]; 35 } 36 } 37 int main() 38 { 39 scanf("%d",&n); 40 41 for (i=1;i<=n;i++) 42 scanf("%d%d",&a[i].x,&a[i].y); 43 sort(a+1,a+1+n,cmp); 44 for (i=1;i<=n;i++) 45 { 46 tmp=0x37373737*2; 47 for (j=i+1;j<=n;j++) 48 if ((i!=j)&&(a[i].x<=a[j].x)&&(a[i].y<=a[j].y)&&(a[j].y<tmp)) 49 { 50 tmp=a[j].y; 51 rd[j]++; 52 link(i,j); 53 } 54 } 55 for (i=1;i<=n;i++) 56 { 57 link(0,i);rd[i]++; 58 link(i,n+1);rd[n+1]++; 59 } 60 t=0;w=1;z[w]=0; 61 while (t!=w) 62 { 63 tot++; 64 t++; 65 id[z[t]]=tot; 66 ID[tot]=z[t]; 67 i=p[z[t]]; 68 while (i) 69 { 70 rd[tt[i]]--; 71 if (rd[tt[i]]==0) 72 { 73 w++;z[w]=tt[i]; 74 } 75 i=pre[i]; 76 } 77 } 78 79 80 for (i=1;i<=tot;i++) 81 for (j=i;j<=tot;j++) 82 Dp(ID[i],ID[j]); 83 printf("%d\n",f[n+1][n+1]-1); 84 }