题目链接:

https://vijos.org/p/1282

https://vijos.org/p/1283

https://vijos.org/p/1284

https://vijos.org/p/1285

T1:佳佳的魔法照片

 纯模拟,我用了两次快排,但是有个数据中k为0也就是无输出,需要注意。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct ding{
  int node,v;
}a[50010];
int n,k,e[15];
inline int read()
{
  int ef=0; char ch;
  while ((ch>'9')||(ch<'0')) ch=getchar();
  while ((ch>='0')&&(ch<='9'))
  {
      ef=ef*10+ch-'0';
      ch=getchar();
  }
  return ef;
}
bool cmp(const ding&x,const ding&y){return (x.v==y.v?x.node<y.node:x.v>y.v);}
bool check()
{
  for (int i=1;i<=n-1;i++)
  if (a[i].v<a[i+1].v) return false;
  return true;
}
int main()
{
  n=read(); k=read(); 
  for (int i=1;i<=10;i++) e[i]=read();
  for (int i=1;i<=n;i++) 
  {
    a[i].v=read();
    a[i].node=i;
  }
  if (!check()) sort(a+1,a+1+n,cmp);
  for (int i=1;i<=n;i++) a[i].v+=e[(i-1)%10+1];
  if (!check()) sort(a+1,a+1+n,cmp);
  for (int i=1;i<=k-1;i++) printf("%d ",a[i]);
  if (k!=0) printf("%d\n",a[k]);
  return 0;
} 

 

T2:佳佳的魔法药水

后来问了一些同学,发现他们大多数都是取当前价格最小的那个(因为它的价格不可能再被更新了),然后去更新可以由它合成的药水的价格(但是要保证另外一种需要的药水,在此之前也已经被选为用来更新的药水了)。然而弱弱的我并没有想到这种方法,于是乎我就打了个dfs搜索。。。

当然,完全硬来肯定是不行的,首先如果当前这瓶药水的价格已经得出了,那下次访问的时候我们就返回上次得到的最优解,在存在环的情况时,我们返回的就是这瓶药水的价格和为1的方案数。

下面是具体程序:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
using namespace std;
char ch;
inline int read()
{
  int ef=0; 
  while ((ch>'9')||(ch<'0')) ch=getchar();
  while ((ch>='0')&&(ch<='9'))
  {
      ef=ef*10+ch-'0';
      ch=getchar();
  }
  return ef;
}
struct ding{
  int a,b;
};
int val[2000],f[2000],g[2000],n,vis[2000];
vector<ding>p[2000];
ding dfs(int x)
{
  if (vis[x]) return ((ding){val[x],1}); //如果有环的话
  if (f[x]) return ((ding){f[x],g[x]});//如果已经做过一次
  vis[x]=true;
  int sum=val[x],sum2=0;
  for (int i=0;i<p[x].size();i++)
  {
      ding now=p[x][i];
    ding w1=dfs(now.a),w2=dfs(now.b);
//更新
    if ((w1.a+w2.a)<sum)
    {
      sum=w1.a+w2.a;
      sum2=w1.b*w2.b;    
    } 
    else if (w1.a+w2.a==sum) sum2+=w1.b*w2.b;
  }
  if (sum==val[x]) sum2++;
  f[x]=sum; g[x]=sum2;
  vis[x]=false;
  return ((ding){f[x],g[x]});
}
int main()
{
  //freopen("hahain.txt","r",stdin);
  //freopen("hahaout.txt","w",stdout);
  n=read();
  for (int i=0;i<=n-1;i++) val[i]=read();
  int a1,b1,c1;
  while (scanf("%d%d%d",&a1,&b1,&c1)!=EOF) p[c1].push_back((ding){a1,b1});
  ding ans=dfs(0);
  printf("%d %d\n",ans.a,ans.b);
  return 0;
}

 

 

T3:佳佳的魔杖

第一次做到这么设的动归,蛮有意义的。

我们设f[i][j]为最后一段起始点在i之前(包括i),终结点在j之前(包括j),i>=j;

很显然f[i][j]=max(f[i-1][j],f[i][j-1](j-1>=i));就是我们并没有做出新的魔杖。

但是如果我们要做出新的魔杖呢?那么f[i][j]=f[i-1][j-1]+segma(m[now](now=i;now<=j))(segma(l[now])要在lo和hi之间)。

它的意思是什么呢?就是我们用i~j的这几段做一根新的魔杖,首先长度需要在lo和hi之间,其次,为了避免冲突,上一次的魔杖最多可能是i-1~j-1或者在这之前。

程序:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int n;
long long l[1010],m[1010],lo,hi,f[1010][1010];
int main()
{
  long long x;
  scanf("%d%lld%lld",&n,&lo,&hi);
  for (int i=1;i<=n;i++) 
  {
      scanf("%lld",&x);
      l[i]+=l[i-1]+x;
  }
  for (int i=1;i<=n;i++)
  {
      scanf("%lld",&x);
      m[i]+=m[i-1]+x;
  }
  for (int i=1;i<=n;i++)
   for (int j=1;j<=n;j++)
   {
     f[i][j]=f[i-1][j];
     if (j-1>=i) f[i][j]=max(f[i][j],f[i][j-1]);
     if ((l[j]-l[i-1]>=lo)&&(l[j]-l[i-1]<=hi)) f[i][j]=max(f[i][j],f[i-1][j-1]+m[j]-m[i-1]);
   }
  printf("%lld\n",f[n][n]);  
  return 0;
}

T4:佳佳的魔法阵

就是直接dfs再加上两个剪枝。

可行性剪枝,如果一个点的上面和下面都被访问过了但是左右还未被访问(或者左右都已访问,可上下还没有),说明左右两块区间在当前走一步之后,无法联通,直接退出。

最优性剪枝:当前的最大值已经大于更新过的答案了,那就直接退出。

程序:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define INF 2100000000
using namespace std;
int node,n,m,ans,k1,k2;
int h[5]={0,-1,1,0,0},l[5]={0,0,0,-1,1};
pair<int,int>f[3000];
bool vis[60][60];
void dfs(int x,int y,int node,int sum)
{
  int now=node%(n*m/2);
  if (node<=n*m/2) f[now]=make_pair(x,y);
  else 
  {
      pair<int,int>p=f[now];
      sum=max(sum,k1*abs(p.first-x)+k2*abs(p.second-y));
      if (sum>ans) return;
  }
  //cout<<x<<" "<<y<<" "<<node<<" "<<sum<<endl;
  if (node==n*m) {ans=min(ans,sum);return;}
  if ((vis[x][y-1]==vis[x][y+1])&&(vis[x-1][y]==vis[x+1][y]))
  {
      bool f1=vis[x-1][y]&vis[x+1][y];
    bool f2=vis[x][y-1]&vis[x][y+1];
    if (f1!=f2) return;
    if (f1&f2) return;
  }
  for (int i=1;i<=4;i++)
  if (!vis[x+h[i]][y+l[i]])
  {
      vis[x+h[i]][y+l[i]]=true;
    dfs(x+h[i],y+l[i],node+1,sum);
    vis[x+h[i]][y+l[i]]=false;
  }
}
int main()
{
  scanf("%d%d%d%d",&n,&m,&k1,&k2);
  for (int i=0;i<=m+1;i++) vis[0][i]=vis[n+1][i]=true;
  for (int i=0;i<=n+1;i++) vis[i][0]=vis[i][m+1]=true;
  for (int i=0;i<=n*m;i++) f[i]=make_pair(0,0);
  ans=INF;
  vis[1][m]=true;
  dfs(1,m,1,0);
  printf("%d\n",ans);
  return 0;
}

 

posted on 2017-04-07 10:57  nhc2014  阅读(440)  评论(0编辑  收藏  举报