1>尼克的任务
额一道挺水的题,愣是做了几个小时
动态规划大致的思路还是找一个转移
换个词就是影响
我们可以明显看出本题的规则:
空暇时,一遇到任务必须挑一个接
求1-n时间内最大空暇时间
所以将任务排序是必要的,两个关键字
再来想象一下当我做到第i个任务时,我在st[i]-(st[i]+t[i]-1)时必然在工作
那么1-(st[i]+t[i]-1)的区间内,
是我上一个任务的f[j]和与j任务之间的时间空暇决定的
则现在的问题是,找出所以合法j任务,然后加上st[i]-st[j]-t[j]
合法的j任务应该满足什么要求呢
st[i]之前已经完成,但是又不能已经完成了太久
这个不能完成太久的条件,其实正着推最容易,
就是j+1任务往后数,最先开始的那个就是,
所以我们需要一个新数组,预处理这个最先开始
当然其实我可以不要这个数组
只要每个当前任务点,去更新后面的任务点
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; int m,n; const int N=10003; struct node { int st,ed;//这里是左闭合,右开 bool operator < (const node & o) const { if(st!=o.st) return st<o.st; else return ed<o.ed; } }d[N]; int f[N]; int main() { scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) scanf("%d%d",&d[i].st ,&d[i].ed ),d[i].ed +=d[i].st ; d[++n].st =m+1,d[n].ed =m+1; sort(d+1,d+n); memset(f,-1,sizeof(f)); int i=2; f[1]=d[1].st -1; while(i<n && d[i].st ==d[1].st ) f[i++]=f[1]; for(i=1;i<n;i++) { if(f[i]==-1) continue; int nx=i+1; while(nx<n && d[nx].st <d[i].ed ) nx++; //printf("%d %d ",d[i].st ,d[i].ed ); int dis=d[nx].st -d[i].ed ; for(int j=nx;j<=n && d[j].st ==d[nx].st ;j++) { f[j]=max(f[i]+dis,f[j]); //,printf(" %d %d %d ",d[j].st ,d[j].ed ,f[j]); //if(d[j].st ==9994) printf("%d %d %d ",i,f[i],dis); } } printf("%d ",f[n]); return 0; }
//倒序做 //为什么? #include<cstdio> #include<cstdlib> #include<algorithm> #include<vector> using namespace std; int m,n; const int N=10003; vector <int> t[N]; int f[N]; int main() { scanf("%d%d",&m,&n); int st,ed; for(int i=1;i<=n;i++) scanf("%d%d",&st ,&ed ),ed +=st ,t[st ].push_back(ed); for(int i=m;i;i--) { int sz=t[i].size(); if(!sz) { f[i]=f[i+1]+1; continue; } for(int j=0;j<sz;j++) { ed=t[i][j]; f[i]=max(f[i],f[ed ]); } } printf("%d ",f[1]); return 0; }
2>相似基因
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> using namespace std; int n1,n2; const int N=103; char s1[N],s2[N]; int d1[N],d2[N]; const int tab[5][5]= { {5,-1,-2,-1,-3}, {-1,5,-3,-2,-4}, {-2,-3,5,-2,-2}, {-1,-2,-2,5,-1}, {-3,-4,-2,-1,0} }; int f[N][N]; int main() { scanf("%d%s",&n1,s1+1); scanf("%d%s",&n2,s2+1); for(int i=1;i<=n1;i++) { if(s1[i]=='A') d1[i]=0; else if(s1[i]=='C') d1[i]=1; else if(s1[i]=='G') d1[i]=2; else if(s1[i]=='T') d1[i]=3; } for(int i=1;i<=n2;i++) { if(s2[i]=='A') d2[i]=0; else if(s2[i]=='C') d2[i]=1; else if(s2[i]=='G') d2[i]=2; else if(s2[i]=='T') d2[i]=3; } memset(f,-0x3f,sizeof(f)); f[0][0]=0;for(int i=1;i<=n2;i++) f[0][i]=f[0][i-1]+tab[d2[i]][4]; for(int i=1;i<=n1;i++) f[i][0]=f[i-1][0]+tab[d1[i]][4]; for(int i=1;i<=n1;i++) for(int j=1;j<=n2;j++) { f[i][j]=max(f[i-1][j-1]+tab[d1[i]][d2[j]], max(f[i-1][j]+tab[d1[i]][4], f[i][j-1]+tab[d2[j]][4]) ); //printf("%d %d %d ",f[i-1][j-1]+tab[d1[i]][d2[j]],f[i-1][j]+tab[d1[i]][4],f[i][j-1]+tab[d2[j]][4]); //printf("%d ",f[i][j]); } printf("%d ",f[n1][n2]); return 0; }
3>分离与合体
就是把单点合并起来,求最值
比较有特色的,就是最后的方案输出:
LYD 请你编程求出最终可以获得的最大总价值,
并按照分离阶段从前到后,区域从左到右的顺序,输出发生分离区域编号。若有多种方案,选择分离区域尽量靠左的方案(也可以理解为输出字典序最小的)。
例如先打印一分为二的区域,然后从左到右打印二分为四的分离区域,然后是四分为八的……
我用的是queue去bfs
#include<cstdio> #include<cstdlib> #include<queue> using namespace std; const int N=303; int n,d[N],f[N][N],pth[N][N]; int max(int a,int b) { return a>b ?a :b; } struct node { int x,y; node(int xx,int yy) { x=xx,y=yy; } node(){} }; void get_path(int l,int r) { queue <node> q; q.push(node(1,n)); while(!q.empty() ) { node nw=q.front(); q.pop(); int cut=pth[nw.x ][nw.y ]; printf("%d ",cut); if(cut>nw.x ) q.push(node(nw.x ,cut)) ; if(cut+1<nw.y ) q.push(node(cut+1,nw.y )) ; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&d[i]); for(int len=1;len<n;len++) for(int i=1,j=1+len;j<=n;i++,j++) { int t=d[i]+d[j]; for(int k=i;k<j;k++) if(t*d[k]+f[i][k]+f[k+1][j] >f[i][j]) f[i][j]=f[i][k]+f[k+1][j]+(d[i]+d[j])*d[k], pth[i][j]=k; } printf("%d ",f[1][n]); get_path(1,n); return 0; }
4>加分二叉树
一道披着树形dp外皮的区间dp
#include<cstdio> #include<cstdlib> #include<cstring> #define ll long long using namespace std; int n; const int N=33; int pth[N][N]; ll d[N],f[N][N]; ll max(ll a,ll b) { return a>b ?a :b; } void get_path(int l,int r) { if(pth[l][r]) { printf("%d ",pth[l][r]); get_path(l,pth[l][r]-1); get_path(pth[l][r]+1,r); } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&d[i]); for(int i=1;i<=n;i++) f[i][i]=d[i],pth[i][i]=i; for(int len=1;len<n;len++) for(int i=1,j=1+len;j<=n;i++,j++) { int t1=f[i+1][j]+d[i],t2=f[i][j-1]+d[j]; if(t1<t2) { if(f[i][j]<t2) f[i][j]=t2,pth[i][j]=j; } else if(f[i][j]<t1) f[i][j]=t1,pth[i][j]=i; for(int k=i+1;k<j;k++) { int t=f[i][k-1]*f[k+1][j] +d[k]; if(t>f[i][j]) f[i][j]=t,pth[i][j]=k; } } printf("%lld ",f[1][n]); get_path(1,n); return 0; }