奋斗群群赛18总结与心得

来源:互联网 发布:mac 看盘软件 编辑:程序博客网 时间:2024/05/22 17:30

  • 总体情况
  • T1
    • 思路
  • T2
    • 思路
  • T3
    • 思路
  • T4
    • 思路
  • T5
    • 思路

总体情况

这次并不是CF上的题,不知道老师昨天经历了什么给我们放了什么鬼题.前4题都是背包,最后一题是树形DP.

T1

http://poj.org/problem?id=1837

思路

01背包.

#include<cstdio>using namespace std;int a[50],b[50],dp[50][10000];int main(){int n,g,i,j,k;scanf("%d%d",&n,&g);dp[0][7500]=1;for (i=1;i<=n;i++) scanf("%d",&a[i]);for (i=1;i<=g;i++) scanf("%d",&b[i]);for (i=1;i<=g;i++) for (j=0;j<=9999;j++) if (dp[i-1][j]) for (k=1;k<=n;k++) dp[i][j+a[k]*b[i]]+=dp[i-1][j];//枚举所有物品以及总力矩的情况,如果存在上一种,则用每个钩子把总力矩更新一遍printf("%d",dp[g][7500]); }

T2

http://poj.org/problem?id=1948

思路

利用背包枚举所有能取到的边长,用海伦公式算出面积的最大值.由于最大边的边长不超过总和的一半,可以从一半开始枚举.

#include<stdio.h>  #include<string.h>  #include<iostream>  #include<algorithm>  #include<cmath>using namespace std;int d[50],dp[1000][1000],sum;int helen(int a,int b,int c){double p=(a+b+c)*1.0/2;return sqrt(p*(p-a)*(p-b)*(p-c))*100;}int main(){int n,i,j,k,ban,answer;scanf("%d",&n);for (dp[0][0]=1,i=1;i<=n;i++) scanf("%d",&d[i]),sum+=d[i];for (ban=sum/2,i=1;i<=n;i++) for (j=ban;j>=0;j--) for (k=j;k>=0;k--) if (j>=d[i]&&dp[j-d[i]][k]||dp[j][k-d[i]]&&k>=d[i]) dp[j][k]=1;for (answer=-1,i=ban;i>=1;i--) for (j=i;j>=1;j--) if (dp[i][j])  {  k=sum-i-j;  if (i+j>k&&i+k>j&&j+k>i) answer=max(answer,helen(i,j,k));  }printf("%d",answer);}

T3

http://acm.split.hdu.edu.cn/showproblem.php?pid=1712

思路

分组背包,也就是对每一组都做一次01背包.

#include<stdio.h>#include<algorithm>#include<cstring>using namespace std;int main(){for (int n,m,i,j,k,a[110][110],dp[110];scanf("%d%d",&n,&m)&&n&&m;printf("%d\n",dp[m]))   {  for (memset(dp,0,sizeof(dp)),i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]);  for (i=1;i<=n;i++) for (j=m;j>=1;j--) for (k=1;k<=j;k++) dp[j]=max(dp[j],dp[j-k]+a[i][k]);  }}

T4

http://poj.org/problem?id=3260

思路

付钱是多重背包,找钱是完全背包.我在3小时29分29秒提交了一次,T了.后来我发现我把一个-号打成了=,居然能过样例!注意多重背包要用优化否则时间会炸掉.

#include<stdio.h>  #include<string.h>  #include<iostream>  #include<algorithm>  #include<cmath>using namespace std;const int index=1<<20;int a[105],b[106],dp1[20560],dp2[20236],n,m,answer;void duochong(int i){int j,k;if (a[i]*b[i]>=m+10000) {for (j=a[i];j<=10000+m;j++) dp2[j]=min(dp2[j],dp2[j-a[i]]+1);return;}for (k=1;k<b[i];b[i]-=k,k*=2) for (j=10000+m;j>=a[i];j--) dp2[j]=min(dp2[j],dp2[j-k*a[i]]+k);//用for循环比起while来精简很多,快速幂也可以这么做for (j=10000+m;j>=a[i];j--) dp2[j]=min(dp2[j],dp2[j-b[i]*a[i]]+b[i]);}int main(){scanf("%d%d",&n,&m);int i,j;for (i=1;i<=n;i++) scanf("%d",&a[i]);for (i=1;i<=n;i++) scanf("%d",&b[i]);memset(dp1,0x3f,sizeof(dp1)),memset(dp2,0x3f,sizeof(dp2));dp1[0]=0,dp2[0]=0;for (i=1;i<=n;i++)   {  for (j=a[i];j<=10000+m;j++) dp1[j]=min(dp1[j],dp1[j-a[i]]+1);  duochong(i);  }for (answer=index,i=m;i<=m+10000;i++) answer=min(dp2[i]+dp1[i-m],answer);printf("%d",answer==index?-1:answer);}

T5

http://poj.org/problem?id=2486

思路

大佬做的题目放弃了.

#include<cstdio>#include<cstring>#include<vector>using namespace std;vector<int> g[1010];int dp[2][1010][210],n,v,val[1010];bool used[1010];void max(int &a,int b){if (a<b) a=b;}void dfs(int s){int i;used[s]=true;for (i=0;i<=v;i++) dp[0][s][i]=dp[1][s][i]=val[s];for (i=0;i<g[s].size();i++)   {  int t=g[s][i];  if (used[t]) continue;  dfs(t);  for (int j=v;j>=0;j--) for (int k=0;k<=j;k++)     {    max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);    max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);    max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);    }  }}int main(){for (int i,a,b;scanf("%d%d",&n,&v)!=EOF;memset(dp,0,sizeof(dp)),memset(used,false,sizeof(used)),dfs(1),printf("%d\n",dp[1][1][v]))  {  for (i=0;i<=1000;i++) g[i].clear();  for (i=1;i<=n;i++) scanf("%d",&val[i]);  for (i=1;i<n;i++) scanf("%d%d",&a,&b),g[a].push_back(b),g[b].push_back(a);  }}