0-1背包问题(回溯法)
题目描述
有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。
输入
多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。
输出
背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2...j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。
样例输入 Copy
5 6 3 6 5 4 2 2 4 6 5 8
样例输出 Copy
15 1 2 3
def bound(i):
left=C-cw;
b=cv;
while i<=n and w[i]<=left:
b+=v[i]
left-=w[i]
i+=1
if i<=n:
b+=left*v[i]/w[i]
return b
def backtrack(t):
global cw,bestv,cv
if t>=n:
if bestv<cv:
bestv=cv
for j in range(n):
bestx[j]=x[j]
else:
if cw+w[t]<=C:
x[t]=1
cv+=v[t]
cw+=w[t]
backtrack(t+1)
x[t]=0
cv-=v[t]
cw-=w[t]
if bound(t+1)>bestv:
x[t]=0
backtrack(t+1)
while True:
n=int(input())
v=list(map(int,input().split()))
w=list(map(int,input().split()))
C=int(input())
w.append(0)
v.append(0)
bestv=0
cw=0
cv=0
v.sort(key=lambda v[0]/w[0] reverse=True)
print(v)
x=[0 for _ in range(n)]
bestx=[0 for _ in range(n)]
backtrack(0)
print(bestv, end=" ")
for j in range(n):
if bestx[j]==1:
print(j+1,end=" ")
旅行售货员(TSP)
题目描述
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路以保证路径最短?
输入
输入两个整数n,m分别代表城市数量,边数量,2<=n<=8,n-1<=m<=2*n
接下来m行每行输入有3个整数x,y,z代表x和y城市之间有一条长为z的路,保证输入的图是连通的,旅行商总是从1城市出发。
输出
要求求出最短的路径,和该路径的长度,如果不存在这样的路径你只需要输出-1。
样例输入 Copy
4 6 1 2 30 1 3 6 1 4 4 2 3 5 2 4 10 3 4 20
样例输出 Copy
1 3 2 4 1 25
#include<bits/stdc++.h>
using namespace std;
const int maxv=110;
int n,k;
int m[maxv];
int bestx[maxv];
int bestc=-1;
int noedge=-1;
double cc;
double g[maxv][maxv];
int ans;
void backstrack(int i){
if(i==n){
if(g[m[n-1]][m[n]]!=noedge&&g[m[n]][1]!=noedge&&(bestc==-1||cc+g[m[n-1]][m[n]]+g[m[n]][1]<bestc)){
for(int j=1;j<=n;++j){
bestx[j]=m[j];
}
++ans;
bestc=cc+g[m[n-1]][m[n]]+g[m[n]][1];
}
}else{
for(int j=i;j<=n;++j){
if(g[m[i-1]][m[j]]!=noedge&&(bestc==-1||cc+g[m[i-1]][m[j]]<bestc)){
swap(m[i],m[j]);
cc+=g[m[i-1]][m[i]];
backstrack(i+1);
cc-=g[m[i-1]][m[i]];
swap(m[i],m[j]);
}
}
}
}
double tsp(){
int i;
for(i=1;i<=n;++i){
m[i]=i;
}
bestc=-1;
cc=0;
backstrack(2);
return bestc;
}
int main()
{
cin>>n>>k;
ans=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
g[i][j]=g[j][i]=-1;
}
}
for(int i=1;i<=k;++i){
int x,y,z;
cin>>x>>y>>z;
g[x][y]=z;
g[y][x]=z;
}
double res=tsp();
if(ans==0){
cout<<-1<<endl;
return 0;
}
for(int i=1;i<=n;++i){
cout<<bestx[i]<<" ";
}
cout<<bestx[1]<<endl;
cout<<bestc<<endl;
return 0;
}
挑选奖品
m,n=map(int,input().split())
a=list(map(int,input().split()))
a.sort(reverse=True)
print(sum(a[:m]))
排列蛋卷
题目描述
刚考完研的TC同学这段时间在家闲得慌,因此他决定学点新手艺。今天他学习的内容是:做蛋卷。
由于是第一次做蛋卷,TC同学做出来蛋卷长短不一。看着这些长度都不一样的蛋卷,TC同学的强迫症又犯了。他希望能够拿出其中部分蛋卷,使得留下来的蛋卷能够按照长度从大到小的次序排列。
请问他最少需要拿出多少根蛋卷?
输入
单组输入,对于每一组测试数据,第1行N表示蛋卷的总数量(n<=1000)。
第2行包含N个正整数,分别表示每一根蛋卷的长度。(单位:厘米)
保证在同一组输入数据中每一根蛋卷的长度均不一样。
输出
输出最少需要拿出的蛋卷数量。
样例输入 Copy
5 15 18 17 11 12
样例输出 Copy
2
n=int(input())
a=[1]*n
b=list(map(int,input().split()))
for i in range(n):
maxlen=0
for j in range(i-1,-1,-1):
if b[i]<b[j] and a[j]>maxlen:
maxlen=a[j]
a[i]=maxlen+1
print(n-max(a))
最大收益
题目描述
小X是一位精明的投资人,他每次都能够做出正确的投资判断。
现在有N个项目,每个项目的总投资额和总收益已知,并且每一个项目都允许小X只投资一部分,当然也就只能拿到一部分收益。
现在小X决定拿出M万元钱来进行投资,请你帮他设计一个算法来计算最大收益和。
输入
单组输入,对于每一组数据,第1行包含两个正整数,分别是M和N,其中M<=10^6,N<=100。
接下来N行每行均包含两个正数(不一定是正整数),第1数字表示第N个项目的总投资额(万元),第2个数字表示第N个项目的总收益(万元),两个数字之间用空格隔开。
输出
小X可以获得的最大收益和(万元,结果四舍五入保留两位小数)。
样例输入 Copy
100 4 50 10 20 10 40 10 50 20
样例输出 Copy
37.50
while True:
try:
n, d = map(float, input().split())
cake=[]
res=0.00
for i in range(int(d)):
a,b=map(float,input().split())
cake.append([a,b])
cake.sort(reverse=True, key=lambda x: x[1] / x[0])
cnt = 0
while n > 0:
w=cake[cnt][0]
v=cake[cnt][1]
cnt = cnt + 1
if n >= w:
res= res + v
n=n-w
else:
res= res + n / w * v
n=0
print("%.2f" % res)
except:
break
X星人的基因
题目描述
X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?
输入
每一组测试数据包含3行,
第1行数字N表示待比较基因序列片段的长度,N<=10^3。
第2行和第3行为两个长度为N的基因序列片段。
输入0表示结束。
输出
两个X星人是否可以结婚,如果可以输出”Yes“,如果不可以输出”No“。
样例输入 Copy
8 A B C D E A B C A C C D C B A E 6 A B C D E E A E D C B B 0
样例输出 Copy
Yes Yes
while True:
n=int(input())
s1,s2=''.join(input().split()),''.join(input().split())
dp=[[0]*(n+1) for _ in range(n+1)]
for i in range(1,n+1):
for j in range(1,n+1):
dp[i][j]=dp[i-1][j-1]+1 if s1[i-1]==s2[j-1] else max(dp[i-1][j],dp[i][j-1])
print('No') if dp[n][n]/n>0.5 else print('Yes')
X星人的礼物
n,m=map(int,input().split())
a=list(map(int,input().split()))
a.sort()
ans=0
i=0
j=n-1
while i<j:
if a[i]+a[j]<=m:
ans,i,j=ans+1,i+1,j-1
else:
ans,j=ans+1,j-1
print(ans) if i!=j else print(ans+1)
X星人的股票
n,m=map(int,input().split())
a=list(map(int,input().split()))
a.sort()
ans=0
i=0
j=n-1
while i<j:
if a[i]+a[j]<=m:
ans,i,j=ans+1,i+1,j-1
else:
ans,j=ans+1,j-1
print(ans) if i!=j else print(ans+1)