1.对抗赛
【问题描述】
程序设计对抗赛设有N(0<N<=50)个价值互不相同的奖品,每个奖品的价值分别为S1,S2,S3,...,Sn(均为不超过100的正整数)。现将他们分给甲乙两队,为了使得甲乙两队得到相同价值的奖品,必须将这N个奖品分成价值相同的两组。
编成要求:对给定N及N个奖品的价值,求出将这N个奖品分成价值相同的两组,共有多少种分发?
例如N=5,S1,S2,S3...,Sn分别为1,3,5,8,9
则可分为{1,3,9}与{5,8},仅有一种分法;
例如N=7,S1,S2,S3...,Sn分别为1,2,3,4,5,6,7
则可分为:
{1,6,7}与{2,3,4,5}
{2,5,7}与{1,3,4,5}
{3,4,7}与{1,2,5,6}
{1,2,4,7}与{3,5,6}
有4种分法。
【输入格式】
N
S1,S2,S3,...,Sn.
【输出格式】
共有多少种分法,无解则输出0;
【输入样例】
7
1 2 3 4 5 6 7
【输出样例】
4
/*求方案总数的01背包,就是把max或者min改为求sum即可,注意f[0]=1--初始化*/ #include<iostream> using namespace std; #include<cstdio> int f[5001],n; int val[51]; int main() { int sum=0; scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&val[i]); sum+=val[i]; } sum/=2; f[0]=1; for(int i=1;i<=n;++i) for(int j=sum;j>=val[i];--j) f[j]+=f[j-val[i]]; cout<<f[sum]/2<<endl;/*注意一定要/2输出,因为方案包括了分组的另一半*/ return 0; }
2.演讲安排
演讲大厅安排:
有一个演讲大厅需要我们管理,演讲者们事先定好了需要演讲的起始时间和中止时间。我们想让演讲大厅得到最大可能的使用。我们要接受一些预定而拒绝其他的预定,目标是使演讲者使用大厅的时间最长。假设在某一时刻一个演讲结束,另一个演讲就可以立即开始。
问题求解:
1、 从文本文件HALL.IN中读入演讲者的申请。
2、 计算演讲大厅最大可能的使用时间。
3、 将结果写入文件HALL.OUT。
输入文件(HALL.IN):
输入文件HALL.IN第一行为一个整数N,N≤5000,表示申请的数目。
以下n行每行包含两个整数p,k,1 ≤ p < k ≤ 10000,表示这个申请的起始时间和中止时间。
输出文件(HALL.OUT):
输出文件HALL.OUT包含一个整数,表示大厅最大可能的使用时间。
输入输出示例:
HALL.IN
12
1 2
3 5
0 4
6 8
7 13
4 6
9 10
9 12
11 14
15 19
14 16
18 20
HALL.OUT
16
注意:可以按照开始排序,也可以按照尾排序,结果是相同的
#include<iostream> using namespace std; #include<cstdio> #include<algorithm> struct Yj{ int p,k; bool operator<(const Yj &x)const { return k<x.k; }/*重载运算符的使用,左边的结构体的k小于右边的结构体的k,左边是指这个Yj不加x.,x.k是指后一个*/ }; Yj yj[5010]; int n; long long int dp[5010]; void input() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d%d",&yj[i].p,&yj[i].k); sort(yj+1,yj+n+1); } void DP() { /*注意:不能初始化f[1]因为这可能不是最优解,要通过循环来找*/ for(int i=1;i<=n;++i) for(int j=0;j<=i-1;++j) if(yj[i].p>=yj[j].k)/*>=是因为 假设在某一时刻一个演讲结束,另一个演讲就可以立即开始。*/ dp[i]=max(dp[i],dp[j]+yj[i].k-yj[i].p); } int main() { freopen("hall.in","r",stdin); // freopen("hall.out","w",stdout); input(); DP(); cout<<dp[n]<<endl; fclose(stdin); fclose(stdout); return 0; }
3.筷子
★☆ 输入文件:chop.in
输出文件:chop.out
简单对比
时间限制:1 s 内存限制:128 MB
A先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A先生家里来了K个客人,A先生留下他们吃晚饭。加上A先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A先生只好清理了一下筷子,共N根,长度为T1,T2,T3,……,TN.现在他想用这些筷子组合成K+3双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A先生了,呵呵)
输入
输入文件共有两行,第一行为两个用空格隔开的整数,表示 N,K(1≤N≤100, 0<K<50),第二行共有N个用空格隔开的整数,为Ti.每个整数为1~50之间的数。
输出
输出文件仅一行。如果凑不齐 K+3双,输出-1,否则输出长度差平方和的最小值。
样例
chop.in
10 1
1 1 2 3 3 3 4 6 10 20
chop.out
5
说明
第一双 1 1
第二双 2 3
第三双 3 3
第四双 4 6
(1-1)^2+(2-3)^2+(3-3)^2+(4-6)^2=5
/*之前错的原因:没有加sort函数,那么从区间i--j挑选一双筷子,虽然是该区间最好,但是对于整体不一定*/ #include<iostream> using namespace std; #include<cstdio> #include<cstring> #include<algorithm> #define N 101 int len[N],p[N][N],f[N][N],n,k; void input() { scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&len[i]); k+=3; } int main() { freopen("chop.in","r",stdin); freopen("chop.out","w",stdout); input(); if(n<2*k) { cout<<-1; return 0; } sort(len+1,len+n+1); memset(p,99,sizeof(p)); for(int i=1;i<=n-1;++i) p[i][i+1]=(len[i]-len[i+1])*(len[i]-len[i+1]); for(int i=1;i<=n-2;++i) for(int j=i+2;j<=n;++j) { int minn=1667457891; for(int l=i+1;l<=j;++l) if((len[i]-len[l])*(len[i]-len[l])<minn) minn=(len[i]-len[l])*(len[i]-len[l]); p[i][j]=minn; } memset(f,99,sizeof(f)); for(int i=2;i<=n;++i) f[i][1]=p[1][i]; for(int j=2;j<=k;++j) for(int i=2*j;i<=n;++i) for(int t=2*(j-1);t<=i-2;++t) f[i][j]=min(f[t][j-1]+p[t+1][i],f[i][j]); cout<<f[n][k]<<endl; fclose(stdin); fclose(stdout); return 0; }
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; int a[101],f[101][101]; int n,k; int main() { scanf("%d%d",&n,&k); k=k+3; for (int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1);//将筷子按长度从短到长排列 if (k*2>n) printf("-1 "); else { for(int i=0;i<=n;i++) { f[i][0]=0; for (int j=1;j<=k;j++) f[i][j]=99999999; } for (int i=2;i<=n;i++) for (int j=1;j<=k;j++)//前i根筷子分为j双时的长度差的最小平方和 f[i][j]=min(f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]),f[i-1][j]); printf("%d",f[n][k]); } return 0; }
4. 花店橱窗布置
每个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数)来表示,空置花瓶的美学值为0。在上述的例子中,花瓶与花束的不同搭配所具有的美学值,可以用如下的表格来表示:
花瓶1 花瓶2 花瓶3 花瓶4 花瓶5
杜鹃花 7 23 -5 -24 16
秋海棠 5 21 -4 10 23
康乃馨 -21 5 -4 -20 20
根据表格,杜鹃花放在花瓶2中,会显得非常好看,但若放在花瓶4中,则显得很难看。
为了取得最佳的美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。
输入文件的第一行是两个整数F和V,分别为花束数和花瓶数(1≤F≤100,F≤V≤100)。接下来是矩阵Aij,它有I行,每行J个整数,Aij表示花束I摆放在花瓶J中的美学值。
输出格式:
输出文件的第一行是一个整数,为最大的美学值;接下来有F行,每行两个数,为那束花放入那个花瓶的编号。
53
2 4 5
/*线性DP*/ #include<iostream> using namespace std; #include<cstdio> int dp[101][101],a[101][101]; int f,v,ping[101]; bool flag[101];int sum; void input() { int maxx=-9999999; scanf("%d%d",&f,&v); for(int i=1;i<=f;++i) for(int j=1;j<=v;++j) { scanf("%d",&a[i][j]); if(i==1) { if(a[i][j]>maxx) maxx=a[i][j]; dp[i][j]=maxx; } } } void search(int,int,int); void DP() { for(int i=2;i<=f;++i) for(int j=i;j<=v;++j) { int maxx=-9999999; for(int t=i-1;t<=j-1;++t) if(dp[i-1][t]+a[i][t+1]>maxx) { maxx=dp[i-1][t]+a[i][t+1];/*把i-1朵花放在t瓶中,把第i朵花放在t+1瓶中的最大值,后面的i不放在t+1瓶中会递推过去*/ } dp[i][j]=maxx; } //cout<<dp[f][v]<<endl; printf("%d ",dp[f][v]); sum=dp[f][v]; search(sum,f,v); } void search(int b,int c,int d)/*寻找方案的过程,也就是逆序最大值的过程*/ { if(c==0) return ; for(int i=c-1;i<=d-1;++i) { if(dp[c-1][i]+a[c][i+1]==b) { d=i+1; break; } } search(b-a[c][d],c-1,d-1); printf("%d ",d); } int main() { input(); DP(); return 0; }
5.友好城市
Problem Description
Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有
且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开
辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,
以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,
被批准的申请尽量多。
Input
输入的第一行为T,表示测试示例的个数。对于每组测试数据,
第1行,一个整数N(1<=N<=5000),表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0<=xi<=10000)
Output
对于每组测试数据,仅一行,输出一个整数,表示政府所能批准的最多申请数。
Sample Input
1
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
Sample Output
4
/*改变了的线段覆盖*/ #include<iostream> using namespace std; #include<cstdio> #include<algorithm> #define N 5001 #include<cstring> int t,n; struct City{ int x,y; int count; bool operator<(const City &p) const {return y<p.y;} }; City city[N]; void input() { memset(city,0,sizeof(city));/*memset也可以给结构体初始化*/ scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d%d",&city[i].x,&city[i].y); if(city[i].x>city[i].y) swap(city[i].x,city[i].y); } sort(city+1,city+n+1); } int main() { scanf("%d",&t); while(t--) { input(); for(int i=1;i<=n;++i) for(int j=0;j<=i-1;++j) if(city[i].x>city[j].y) city[i].count=max(city[j].count+1,city[i].count); int maxx=-1; for(int i=1;i<=n;++i) if(city[i].count>maxx)/*因为不知道到底哪个城市是最后一个可以建设大桥的,所以搜索一遍*/ maxx=city[i].count; printf("%d ",maxx); } return 0; }
6.护卫队(cojs)
输入文件第一行包含三个正整数(用空格隔开),第一个整数表示该桥所能承受的最大载重量(用吨表示);第二个整数表示该桥长度(用千米表示);第三个整数表示该护卫队中车辆的总数(n<1000)。接下来的几行中,每行包含两个正整数W和S(用空格隔开),W表示该车的重量(用吨表示),S表示该车过桥能达到的最快速度(用千米/小时表示)。车子的重量和速度是按车子排队等候时的顺序给出的。
输出格式:
输出文件应该是一个实数,四舍五入精确到小数点后1位,表示整个护卫车队通过该桥所需的最短时间(用分钟表示)。
75.0
1 /*超时原因:未找到最好的DP 2 错误原因:中间值溢出,max不够大等等 3 */ 4 #include<iostream> 5 using namespace std; 6 #include<cstdio> 7 #include<cstring> 8 #include<cmath> 9 #define N 1001 10 #define INF 21474836472147483647 11 long long int W,L,n; 12 struct Car{ 13 long long int w; 14 double t,s; 15 }; 16 long long int sum[N]; 17 Car car[N]; 18 double dp[N][N]; 19 double p[N][N]; 20 void input() 21 { 22 cin>>W>>L>>n; 23 //scanf("%d%d%d",&W,&L,&n); 24 int i; 25 for(i=1;i<=n;++i) 26 { 27 scanf("%d%lf",&car[i].w,&car[i].s); 28 car[i].t=L/car[i].s*60; 29 sum[i]=sum[i-1]+car[i].w; 30 } 31 } 32 void dop() 33 { 34 for(int i=1;i<=n;++i) 35 for(int j=i;j<=n;++j) 36 { 37 if(sum[j]-sum[i-1]<=W) 38 p[i][j]=max(car[j].t,p[i][j-1]); 39 else { 40 for(int l=j;l<=n;++l) 41 p[i][l]=INF; 42 break; 43 44 } 45 } 46 } 47 int k; 48 void DP() 49 { 50 51 k=(sum[n]/W)*2; 52 if(k>n) 53 k=n; 54 int i,j,l; 55 memset(dp,127,sizeof(dp)); 56 for(i=1;i<=n;++i) 57 dp[i][0]=dp[0][i]=0; 58 for(i=1;i<=n;++i) 59 dp[i][1]=p[1][i]; 60 for(j=2;j<=k;++j) 61 for(i=j;i<=n;++i) 62 for(l=j-1;l<=i-1;++l) 63 dp[i][j]=min(dp[i][j],dp[l][j-1]+p[l+1][i]); 64 65 } 66 double MIN=21474836472147483647; 67 int main() 68 { 69 freopen("convoy.in","r",stdin); 70 freopen("convoy.out","w",stdout); 71 input(); 72 dop(); 73 DP(); 74 int i; 75 for(i=1;i<=k;++i) 76 MIN=min(MIN,dp[n][i]); 77 printf("%0.1f ",MIN); 78 fclose(stdin); 79 fclose(stdout); 80 return 0; 81 }
1 /*正确简洁的思路:f[n]以每个车作为划分点,每个车可以单独作为一个车队,也可以与之前形成的最后一个车队(多种情况)组合*/ 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 #include<cstring> 6 #define N 1001 7 double f[N]; 8 double vmin[N][N]; 9 long long int sum[N]; 10 struct Car { 11 long long int w; 12 double s; 13 }; 14 long long int w,l,n; 15 Car car[N]; 16 void input() 17 { 18 cin>>w>>l>>n; 19 //memset(vmin,99,sizeof(vmin)); 20 for(int i=1;i<=n;++i) 21 { 22 cin>>car[i].w>>car[i].s; 23 vmin[i][i]=car[i].s; 24 sum[i]=sum[i-1]+car[i].w; 25 } 26 for(int i=1;i<=n;++i) 27 for(int j=i+1;j<=n;++j) 28 if(sum[j]-sum[i-1]<=w)/*i--j这个区间内速度最小的车的速度*/ 29 vmin[i][j]=min(car[j].s,vmin[i][j-1]); 30 31 } 32 void DP() 33 { 34 f[1]=l/car[1].s;//边界 35 for(int i=2;i<=n;++i) 36 { 37 f[i]=f[i-1]+l/car[i].s;//先把第i个单独作为一个车队 38 for(int j=1;j<=i;++j) 39 if(sum[i]-sum[j]<=w) 40 f[i]=min(f[i],f[j-1]+l/vmin[j][i]); /*注意要确保更新的量可以使前i个车作为一个车队,就是f[0]+...*/ 41 } 42 printf("%.1f ",f[n]*60); /*题目要求输出分钟*/ 43 } 44 int main() 45 { 46 freopen("convoy.in","r",stdin); 47 freopen("convoy.out","w",stdout); 48 input(); 49 DP(); 50 fclose(stdin); 51 fclose(stdout); 52 return 0; 53 }
输入文件mine.in有若干行。
第1行只有一个数字,表示地窖的个数N。
第2行有N个数,分别表示每个地窖中的地雷个数。
第3行至第N+1行表示地窖之间的连接情况:
第3行有n-1个数(0或1),表示第一个地窖至第2个、第3个、…、第n个地窖有否路径连接。如第3行为1 1 0 0 0 … 0,则表示第1个地窖至第2个地窖有路径,至第3个地窖有路径,至第4个地窖、第5个、…、第n个地窖没有路径。
第4行有n-2个数,表示第二个地窖至第3个、第4个、…、第n个地窖有否路径连接。
… …
第n+1行有1个数,表示第n-1个地窖至第n个地窖有否路径连接。(为0表示没有路径,为1表示有路径)。
输出格式:
输出文件wdl.out有两行数据。
第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。
第二行只有一个数,表示能挖到的最多地雷数。
/*题目中的样例说明:只能从编号大的点向编号小的点挖,这是题目中没有说的, */ #include<iostream> #include<cstdio> using namespace std; #include<cstring> #define N 21 int flag[N][N]; int n,num[N]; int f[N],pre[N],path; void input() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&num[i]); f[i]=num[i]; } for(int i=1;i<=n-1;++i) for(int j=1+i;j<=n;++j) scanf("%d",&flag[i][j]);/*把路径都设为单向的*/ } void DP() {/*类似于数塔的自下向上的推导,并且记录路径*/ for(int i=n-1;i>=1;--i) { int maxx=0; for(int j=i+1;j<=n;++j) { if(f[j]>maxx&&flag[i][j]) { maxx=f[j]; path=j; } } f[i]+=maxx; pre[i]=path; } } void print() { int p; int maxx=0; for(int i=1;i<=n;++i) if(f[i]>maxx) { maxx=f[i]; p=i; } while(p) { printf("%d ",p); p=pre[p]; } printf(" %d",maxx); return ; } int main() { input(); DP(); print(); return 0; }