[区间记忆化dp入门][Bribe the Prisoners SPOJ - GCJ1C09C][Codeforces Round #505D (rated, Div. 1 + Div. 2, ba]

Bribe the Prisoners SPOJ - GCJ1C09C

作为这类题代表,f[i][j]代表第i点到第j点单独处理的最值

这题关键:释放某个囚犯后,就把囚犯分成两段,两段互相独立 

这类dp问题的突破口在于一个点能把问题分成两段,两段互相独立,这两段的限制条件只与l-1,r+1有关,记忆化搜索,时间复杂度o(n*n*n)

#include
using namespace std;
long long n,t,T,min1,m,a[100000],f[1000][1000];
long long dfs(int l,int r)
  { // cout<>T;
  while (T--)
  {   t++;
    memset(f,0,sizeof(f));
     cin>>n>>m;
     min1=1e15;
     a[m+1]=0; a[m+2]=n+1;
     for (int i=1;i<=m;i++)  cin>>a[i];
     m=m+2;
     sort(a+1,a+1+m);
     for (int i=2;i<=m-1;i++)
	  min1=min(min1,(n-1)+dfs(2,i-1)+dfs(i+1,m-1));
	 cout<<"Case #"<

 [Codeforces Round #505D (rated, Div. 1 + Div. 2, ba]

其实是一道很简单的区间dp记忆化搜索,太久没写这种类型的了。

定义二叉排序树

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;

(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

(3)左、右子树也分别为二叉排序树;

显然会想到排序, 预处理两点之间是否有>1的gcd

考虑任何一个点作为根节点,只要两边分别满足条件即可,(同时两边有一个树与根节点不互质,这个只要在找子区间根节点是特判就行)(两边互相独立不影响)  

节点两边分别为一段连续区间(且这段区间的根节点一定是r+1或者l-1

f[i][j][0/1]代表i-j区间是否可能作为根节点的左子树/右子树

#include
using namespace std;
int  n,t,a[1000],g[1000][1000],f[1000][1000][2],v[1000][1000][2];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
inline int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int calc(int l,int r,int c)
{if (c==0)  return r+1;  else return l-1;}  
int dfs(int l,int r,int c)
{ if (l>r) return 1;
  if (v[l][r][c])  return f[l][r][c];
//注意因为f[l][r][c]可能处理过后值为0;所以用v[i][j][r]判断是否处理过(调好久原因)
  v[l][r][c]=1;
  int p=0;
  for (int  i=l;i<=r;i++)
  if (g[i][calc(l,r,c)] && dfs(l,i-1,0) && dfs(i+1,r,1))
  {p=1; break;} 
  f[l][r][c]=p; 
  return p;
}
int main()
{  n=read();
   for (int i=1;i<=n;i++)  a[i]=read();
   sort(a+1,a+1+n);
   for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
     if (gcd(a[i],a[j])>1) g[i][j]=1; else g[i][j]=0;
   for (int i=1;i<=n;i++)
   if (dfs(1,i-1,0)  && dfs(i+1,n,1)) {t=1;break;}
   if (t==1)  cout<<"Yes"<

 

你可能感兴趣的:(dp想法)