专题:DP杂题1
点击题号进入题面
---
A
/* dp[i,j] i个设备 j最小带宽 只能转移到dp[i-1][j]+大于等于j带宽的设备 */ #include <stdio.h> #include <math.h> #include <iostream> #include <string.h> using namespace std; const int maxn=1e3+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int dp[maxn][maxn]; int num[maxn]; int p[maxn][maxn],f[maxn][maxn]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif cin>>casn; while(casn--){ int mx=0; cin>>n; for(int i=1;i<=n;i++){ cin>>num[i]; for(int j=1;j<=num[i];j++){ cin>>f[i][j]>>p[i][j]; mx=max(f[i][j],mx); } } memset(dp,0,sizeof dp); for(int i=1;i<=n;i++){ for(int j=0;j<=mx;j++){ int mn=INF; for(int k=1;k<=num[i];k++){ if(j<=f[i][k]){ mn=min(dp[i-1][j]+p[i][k],mn); } } dp[i][j]=mn; } } double ans=0; for(int i=1;i<=mx;i++){ ans=max(ans,i/(double)dp[n][i]); } printf("%.3f\n",ans); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
B
/* 把二维看成一维 先枚举行的起点和终点 再把起点行和终点行间每一列的数值压缩到每一个点上 然后求一个最长连续字段和 复杂度O(n^3) */ #include <string.h> #include <stdio.h> #include <iostream> #include <algorithm> using namespace std; const int maxn=1e3+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; #define ll long long int casn,n,m,k; int smax(int a[],int len){ int mx=0,sub=0; for(int i=1;i<=len;i++){ sub=max(a[i],sub+a[i]); mx=max(sub,mx); } return mx; } int arr[maxn]; int dp[maxn][maxn]; int main(){ #define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(~scanf("%d",&n)){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&dp[i][j]); } } int ans=-INF; for(int i=1;i<=n;i++){ memset(arr,0,sizeof arr); for(int j=i;j<=n;j++){ for(int k=1;k<=n;k++){ arr[k]+=dp[j][k]; } ans=max(ans,smax(arr,n)); } } printf("%d\n",ans); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
C
/* 交叉的工作是必须要完成的 而所有的不交叉工作都可以同时完成 那最晚完成的就是交叉次数最多的走廊区域了 注意由于走廊是公用的,所以南北的房间实际上一样 映射到1-200的区域就行了 */ #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=1e3+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int cost[maxn]; int main(){ // #define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif scanf("%d",&casn); while(casn--){ scanf("%d",&n); memset(cost,0,sizeof cost); for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y); if(x>y) swap(x,y); x=(x>>1)+(x&1); y=(y>>1)+(y&1); for(int j=x;j<=y;j++){ cost[j]++; } } int ans=0; for(int i=1;i<=400;i++){ ans=max(cost[i],ans); } printf("%d\n",ans*10); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
D
/* 有向图的floyd 跑完之后枚举一遍起点 保存最小最长边 输出的时候特判一下 */ #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int maxn=1e2+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int num[maxn]; int dp[maxn][maxn]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(scanf("%d",&n),n){ memset(dp,INF,sizeof dp); for(int i=1;i<=n;i++){ scanf("%d",&num[i]); for(int j=0;j<num[i];j++){ int a,b; scanf("%d%d",&a,&b); dp[i][a]=b; } } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ int t=dp[i][k]+dp[k][j]; dp[i][j]=min(dp[i][j],t); } } } int flag=0,ans=INF,id=0; for(int i=1;i<=n;i++){ int t=0; for(int j=1;j<=n;j++){ if(i==j) continue; t=max(t,dp[i][j]); } if(t<ans) id=i,ans=t; } if(!id) puts("disjoint"); else printf("%d %d\n",id,ans); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
E
/* 如果i在list里,则进行dfs 如果dfs可以推出失败.则保存答案 dfs: 状态很显然是20个数字那些不能选 状态种类不多且每个状态只有2种情况 考虑状态压缩,每一位保存该位置的数字是否可以使用 用记忆化搜索,标记2进制所保存的状态的输赢 不断dfs,换选手,返回下一个选手是输还是赢即可 如果下一个选手输,则当前为必胜态,以此类推 */ #include <string.h> #include <algorithm> #include <stdio.h> using namespace std; const int maxn=2e6+10; const int maxm=1e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; int num[30]; int dp[maxn]; bool vis[30]; int ans[30]; int cps(bool vis[]){ int stt=0; for(int i=2;i<=20;i++){ stt|=vis[i]; stt<<=1; } return stt>>1; } bool dfs(int now,bool vis[]){ bool vis2[30]; memcpy(vis2,vis,25); vis2[now]=false; for(int i=2;i+now<=20;i++){ if(!vis2[i])vis2[i+now]=false; } int stt=cps(vis2); if(dp[stt]){ return dp[stt]>0; } for(int i=2;i<=20;i++){ if(vis2[i]&&!dfs(i,vis2)) return dp[stt]=1; } dp[stt]=-1; return false; } int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif memset(dp,0,sizeof dp); while(scanf("%d",&n),n){ memset(vis,0,sizeof vis); for(int i=1;i<=n;i++){ scanf("%d",&num[i]); vis[num[i]]=true; } int cnt=0; int stt=cps(vis); for(int i=2;i<=20;i++){ if(vis[i]&&!dfs(i,vis)) ans[cnt++]=i; } printf("Test Case #%d\n",++casn); if(cnt){ printf("The winning moves are:"); for(int i=0;i<cnt;i++){ printf(" %d",ans[i]); } puts(""); }else dp[stt]=-1,puts("There's no winning move."); puts(""); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }