17HNUCM计科练习16题解(0-1背包回溯,tsp)

目录

初中化学

简单的几何学

0-1背包问题(回溯法)

旅行售货员(TSP)


初中化学

能够进入湖南中医药大学这样的高等院校,我相信你对单质铁与硫酸铜的置换反应并不陌生,我们依稀记得要分成三种情况讨论

  1. 单质铁过量
  2. 硫酸铜溶液过量
  3. 恰好反应完

既然我们现在已经是大学生了,我们应该学会使用成熟的方法来解决问题。

Fe+CuSO4⟹FeSO4+Cu

假设现在有x克单质铁,y克质量分数为z%的硫酸铜溶液,现将单质铁放入装有硫酸铜溶液的烧杯中,待充分反应后,将此烧杯称重(烧杯重50g),你能写出一个程序自动计算称重的结果吗?

可能用到的相对原子质量如下:

符号相对原子质量
O16
S32
Fe56
Cu64

 

输入

单组输入数据

x y z(0<x,y<10000,0<z<100)(0<x,y<10000,0<z<100),保证x和y都为整数

输出

输出一行,代表称重的结果(保留整数)。

样例输入 Copy

56 1635 4.68

样例输出 Copy

1741
#include<bits/stdc++.h>//没产生气体,所以质量守恒
using namespace std;
int main(){
    int x,y,z;
    while(cin>>x>>y>>z){
        int s;
        s=x+y+50;
        cout<<s<<endl;
    }
    return 0;
}

 

简单的几何学

题目描述

这是一个十分简单的几何学题目。现在给出N个点的坐标(x,y),保证x和y都是整数,你的任务是判断这N个点是否能构成正N边形。

输入

单组输入数据

第一行是N,(2<N<1000)

接下来有N行,每行两个数,代表这个点的坐标(x,y)

−1000≤x,y≤1000 且保证都为整数

 

输出

输出一行结果
如果可以构成正N边形,输出Yes,否则输出No

样例输入 Copy

4
0 50
0 -50
50 0
-50 0

样例输出 Copy

Yes
#include<bits/stdc++.h>//这个题只考虑正方形就行了,因为"整数"
using namespace std;
double aa(int a,int b,int c,int d){
    return sqrt((double)(a-c)*(a-c)+(double)(b-d)*(b-d));
}
int main(){
    int n;
    while(cin>>n){
        int p[n][2];
        double e[10];
        int ans=0;
        for(int i=0;i<n;i++){
            cin>>p[i][0]>>p[i][1];
        }
        if(n!=4) {
            cout<<"No"<<endl;
            continue;
        }
        for(int i=0;i<n-1;i++){
            for(int j=i+1;j<n;j++){
                    e[ans++]=aa(p[i][0],p[i][1],p[j][0],p[j][1]);
                }
        }
        sort(e,e+ans);
        if(e[0]==e[1]&&e[1]==e[2]&&e[2]==e[3]&&e[4]==e[5]&&e[4]!=e[0])
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

 

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
#include<bits/stdc++.h>
using namespace std;
typedef struct aa{
    int w,v;
    double vw;
    int id;
};
aa a[35];
int c;
int n;
double cw;
double cv;
double bestp;
int bestx[35];
int x[35];

bool cmp(aa x,aa y){
    return x.vw>y.vw;
}
void init(){
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    memset(bestx,0,sizeof(bestx));
    c=0;
    cv=cw=bestp=0;
}

double bound(int i){
    int cleft=c-cw;
	int b=cv;
	while(i<n&&a[i].w<=cleft)
	{
		cleft-=a[i].w;
		b+=a[i].v;
		i++;
	}
	if(i<n)
        b+=cleft*a[i].vw;
	return b;
}
void backtrack(int i){
    if(i+1>n)
	{
		bestp=cv;
        for(int j=0;j<n;j++)
            bestx[j]=x[j];
		return;
	}
	if(cw+a[i].w<=c)
	{
	    x[i]=1;
		cw+=a[i].w;
		cv+=a[i].v;
		backtrack(i+1);
		x[i]=0;
		cw-=a[i].w;
		cv-=a[i].v;
	}

	if(bound(i+1)>bestp)
	{
		backtrack(i+1);
	}
}
int main()
{
    int i;
    while(cin>>n){
        init();
        for(i=0;i<n;++i)
            cin>>a[i].v;
        for(i=0;i<n;++i){
            cin>>a[i].w;
            a[i].id=i+1;
            a[i].vw=a[i].v*1.0/a[i].w;
        }
        cin>>c;
        sort(a,a+n,cmp);
        backtrack(0);
        int s[35];
        int ans=0;
        for(i=0;i<n;++i)
        {
            if(bestx[i])
                s[ans++]=a[i].id;
        }
        sort(s,s+ans);
        cout<<bestp;
        for(i=0;i<ans;++i)
            cout<<" "<<s[i];
        cout<<endl;
    }
    return 0;
}

 

旅行售货员(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 maxn=105;
const double Max=100000;
int n,m;
int x[maxn];
int bestx[maxn];
double bestc;
double cc;
double a[maxn][maxn];
int sum;
void backstrack(int i){
    if(i==n){
        if(a[x[n-1]][x[n]]<Max&&a[x[n]][1]<Max&&(bestc==Max||cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc)){
            for(int j=1;j<=n;++j){
                bestx[j]=x[j];
            }
            ++sum;
            bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];
        }
    }else{
        for(int j=i;j<=n;++j){
            if(a[x[i-1]][x[j]]<Max&&(bestc==Max||cc+a[x[i-1]][x[j]]<bestc)){
                swap(x[i],x[j]);
                cc+=a[x[i-1]][x[i]];
                backstrack(i+1);
                cc-=a[x[i-1]][x[i]];
                swap(x[i],x[j]);
            }
        }
    }
}
double tsp(){
    int i;
    for(i=1;i<=n;++i){
        x[i]=i;
    }
    bestc=Max;
    cc=0;
    backstrack(2);
    return bestc;
}
int main()
{
    cin>>n>>m;
    sum=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            a[i][j]=a[j][i]=Max;
        }
    }
    for(int i=1;i<=m;++i){
        int x,y,z;
        cin>>x>>y>>z;
        a[x][y]=z;
        a[y][x]=z;
    }
    double ans=tsp();
    if(sum==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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值