W = 10
。求在不超过背包容量的前提下,把哪些物品放入背包才能获得最大价值。struct Node{ //定义节点,记录当前节点的解信息
int cp,rp; //cp背包的物品总价值,rp剩余物品的总价值
int rw; //剩余容量
int id; //物品号
bool x[N]; //解向量
Node() {memset(x,0,sizfof(x));} //将解向量初始化为0
Node(int _cp, int _rp, int _rw, int _id){
cp = _cp;
rp = _rp;
rw = _rw;
id = _id;
}
};
struct Goods{ //物品
int wight; //重量
int value; //价值
}goods[N]
#include
#include
#include
using namespace std;
const int N=10;
bool bestx[N];
//定义结点。每个节点来记录当前的解。
struct Node{
int cp,rp; //cp为当前装入背包的物品总价值,rp为剩余物品的总价值
int rw; //剩余容量
int id; //物品号
bool x[N];//解向量
Node(){}
Node(int _cp,int _rp,int _rw,int _id){
cp=_cp;
rp=_rp;
rw=_rw;
id=_id;
memset(x,0,sizeof(x));//解向量初始化为0
}
};
struct Goods{//物品
int weight;//重量
int value;//价值
}goods[N];
int bestp,W,n,sumw,sumv;
/*
bestp用来记录最优解
W为背包最大容量。
n为物品的个数。
sumw为所有物品的总重量。
sumv为所有物品的总价值。
*/
int bfs();//队列式分支限界法
int main(){
cin>>n>>W;//输入物品的个数和背包的容量
bestp=0; //bestv用来记录最优解
sumw=0; //sumw为所有物品的总重量。
sumv=0; //sumv为所有物品的总价值
for(int i=1;i<=n;i++){//输入每个物品的重量和价值,用空格分开
cin>>goods[i].weight>>goods[i].value;//输入第i件物品的重量和价值。
sumw+=goods[i].weight;
sumv+=goods[i].value;
}
if(sumw<=W){
bestp=sumv;
cout<<"放入背包的物品最大价值为: "<<bestp<<endl;
return 0;
}
bfs();
cout<<"放入背包的物品最大价值为: "<<bestp<<endl;
cout<<"放入背包的物品序号为: ";
for(int i=1;i<=n;i++){// 输出最优解
if(bestx[i])
cout<<i<<" ";
}
return 0;
}
int bfs(){//队列式分支限界法
int t,tcp,trp,trw;//当前处理的物品序号t,装入背包物品价值tcp,剩余容量trw
queue<Node> q; //创建一个普通队列(先进先出)
q.push(Node(0,sumv,W,1)); //压入一个初始节点
while(!q.empty()){
Node livenode,lchild,rchild;//定义三个结点型变量
livenode=q.front();//取出队头元素作为当前扩展结点livenode
q.pop(); //队头元素出队
t=livenode.id;//当前处理的物品序号
// 搜到最后一个物品的时候不需要往下搜索
// 如果当前的背包没有剩余容量(已经装满)了,不再扩展
if(t>n||livenode.rw==0){
if(livenode.cp>=bestp){//更新最优解和最优值
for(int i=1;i<=n;i++)
bestx[i]=livenode.x[i];
bestp=livenode.cp;
}
continue;
}
if(livenode.cp+livenode.rp<bestp)//判断当前结点是否满足限界条件,如果不满足不再扩展
continue;
tcp=livenode.cp; //当前背包中的价值
trp=livenode.rp-goods[t].value; //不管当前物品装入与否,剩余价值都会减少。
trw=livenode.rw; //背包剩余容量
if(trw>=goods[t].weight){ //扩展左孩子,满足约束条件,可以放入背包
lchild.rw=trw-goods[t].weight;
lchild.cp=tcp+goods[t].value;
lchild=Node(lchild.cp,trp,lchild.rw,t+1);
for(int i=1;i<t;i++)//复制以前的解向量
lchild.x[i]=livenode.x[i];
lchild.x[t]=true;
if(lchild.cp>bestp)//比最优值大才更新
bestp=lchild.cp;
q.push(lchild);//左孩子入队
}
if(tcp+trp>=bestp){//扩展右孩子,满足限界条件,不放入背包
rchild=Node(tcp,trp,trw,t+1);
for(int i=1;i<t;i++)//复制以前的解向量
rchild.x[i]=livenode.x[i];
rchild.x[t]=false;
q.push(rchild);//右孩子入队
}
}
return bestp;//返回最优值
}
输入:
4 10
2 6 5 3 4 5 2 4
输出:
放入背包的物品最大价值为: 15
放入背包的物品序号为: 1 3 4
cw+w[i]
≤ \leq ≤ W
up = cp + rp'
≥ \geq ≥ bestp
struct Node{ //定义节点,记录当前节点的解信息
int cp; //cp背包的物品总价值,rp剩余物品的总价值
double up; //价值上界
int rw; //剩余容量
int id; //物品号
bool x[N]; //解向量
Node() {}
Node(int _cp, double _up, int _rw, int _id){
cp = _cp;
up = _up;
rw = _rw;
id = _id;
memset(x,0,sizfof(x));
}
};
struct Goods{//物品
int weight;//重量
int value;//价值
}goods[N];
struct Object{ //辅助物品结构体,用于按单位重量价值(价值/重量比)排序
int id; //序号
double d; //单位重量价值
}S[N];
bool cmp(Object a1,Object a2){ //排序优先级,按照物品的单位重量价值由大到小排序
return a1.d>a2.d;
}
bool operator <(const Node &a, const Node &b){ //队列优先级,up越大越优先
return a.up < b.up;
}
double Bound(Node tnode){
double maxvalue = tnode.cp; //已装入背包的物品价值
int t = tnode.id; //排序后序号
double left = tnode.rw; //剩余容量
while(t <= n && w[t] <= left){
maxvalue+=v[t];
left-=w[t++];
}
if(t <= n){
maxvalue+=double(v[t])/w[t]*left;
}
return maxvalue;
}
#include
#include
#include
#include
#include
using namespace std;
const int N=10;
bool bestx[N]; //记录最优解
int w[N],v[N];//辅助数组,用于存储排序后的重量和价值
struct Node{//定义结点,记录当前结点的解信息
int cp; //已装入背包的物品价值
double up; //价值上界
int rw; //背包剩余容量
int id; //物品号
bool x[N];
Node() {}
Node(int _cp,double _up,int _rw,int _id){
cp=_cp;
up=_up;
rw=_rw;
id=_id;
memset(x, 0, sizeof(x));
}
};
struct Goods{ //物品结构体
int weight;//重量
int value;//价值
}goods[N];
struct Object{//辅助物品结构体,用于按单位重量价值(价值/重量比)排序
int id; //序号
double d;//单位重量价值
}S[N];
bool cmp(Object a1,Object a2){//排序优先级,按照物品单位重量价值由大到小排序
return a1.d>a2.d;
}
bool operator <(const Node &a, const Node &b){//队列优先级。up越大越优先
return a.up<b.up;
}
int bestp,W,n,sumw,sumv;
/*
bestv 用来记录最优解。
W为背包的最大容量。
n为物品的个数。
sumw为所有物品的总重量。
sumv为所有物品的总价值。
*/
double Bound(Node tnode){//计算节点的上界
double maxvalue=tnode.cp;//已装入背包物品价值
int t=tnode.id;//排序后序号
double left=tnode.rw;//剩余容量
while(t<=n&&w[t]<=left){
maxvalue+=v[t];
left-=w[t++];
}
if(t<=n)
maxvalue+=double(v[t])/w[t]*left;
return maxvalue;
}
int priorbfs(){//优先队列式分支限界法
int t,tcp,trw;//当前处理的物品序号t,当前装入背包物品价值tcp,当前剩余容量trw
double tup; //当前价值上界tup
priority_queue<Node> q; //创建一个优先队列
q.push(Node(0,sumv,W,1));//初始化,根结点加入优先队列
while(!q.empty()){
Node livenode, lchild, rchild;//定义三个结点型变量
livenode=q.top();//取出队头元素作为当前扩展结点livenode
q.pop(); //队头元素出队
t=livenode.id;//当前处理的物品序号
// 搜到最后一个物品的时候不需要往下搜索。
// 如果当前的背包没有剩余容量(已经装满)了,不再扩展。
if(t>n||livenode.rw==0){
if(livenode.cp>=bestp){//更新最优解和最优值
for(int i=1;i<=n;i++)
bestx[i]=livenode.x[i];
bestp=livenode.cp;
}
continue;
}
if(livenode.up<bestp)//如果不满足不再扩展
continue;
tcp=livenode.cp; //当前背包中的价值
trw=livenode.rw; //背包剩余容量
if(trw>=w[t]){ //扩展左孩子,满足约束条件,可以放入背包
lchild.cp=tcp+v[t];
lchild.rw=trw-w[t];
lchild.id=t+1;
tup=Bound(lchild); //计算左孩子上界
lchild=Node(lchild.cp,tup,lchild.rw,lchild.id);
for(int i=1;i<=n;i++)//复制以前的解向量
lchild.x[i]=livenode.x[i];
lchild.x[t]=true;
if(lchild.cp>bestp)//比最优值大才更新
bestp=lchild.cp;
q.push(lchild);//左孩子入队
}
rchild.cp=tcp;
rchild.rw=trw;
rchild.id=t+1;
tup=Bound(rchild);//计算右孩子上界
if(tup>=bestp){//扩展右孩子,满足限界条件,不放入
rchild=Node(tcp,tup,trw,t+1);
for(int i=1;i<=n;i++)//复制以前的解向量
rchild.x[i]=livenode.x[i];
rchild.x[t]=false;
q.push(rchild);//右孩子入队
}
}
return bestp;//返回最优值。
}
int main(){
bestp=0; //bestv用来记录最优解
sumw=0; //sumw为所有物品的总重量。
sumv=0; //sumv为所有物品的总价值
cin>>n>>W;
for(int i=1;i<=n;i++){
cin>>goods[i].weight>>goods[i].value;//输入第i件物品的重量和价值。
sumw+=goods[i].weight;
sumv+=goods[i].value;
S[i-1].id=i;
S[i-1].d=1.0*goods[i].value/goods[i].weight;
}
if(sumw<=W){
bestp=sumv;
cout<<"放入背包的物品最大价值为: "<<bestp<<endl;
return 0;
}
sort(S,S+n,cmp);//按价值重量比非递增排序
for(int i=1;i<=n;i++){//把排序后的数据传递给辅助数组
w[i]=goods[S[i-1].id].weight;
v[i]=goods[S[i-1].id].value;
}
priorbfs();//优先队列分支限界法
cout<<"放入背包的物品最大价值为: "<<bestp<<endl;
cout<<"放入背包的物品序号为: ";
for(int i=1;i<=n;i++){ //输出最优解
if(bestx[i])
cout<<S[i-1].id<<" ";//输出原物品序号(排序前的)
}
return 0;
}
输入:
4 10
2 6 5 3 4 5 2 4
输出:
放入背包的物品最大价值为: 15
放入背包的物品序号为: 1 3 4
用一个二维数组表示一个迷宫,其中1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,编写程序,找出从左上角到右下角的最短路线。
输入:一个 5 × 5 5 \times 5 5×5的二维数组,表示一个迷宫。数据保证有唯一解。
输出:从左上角到右下角的最短路径,格式如以下输出样例所示。
#include
#include
using namespace std;
int mp[5][5],vis[5][5];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
int x,y;
};
node pre[10][10];
void bfs(); //广度搜索
void print(node cur); //打印结果
int main(){
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
scanf("%d",&mp[i][j]);
bfs();
node ed;
ed.x=ed.y=4;
print(ed);
return 0;
}
void bfs(){
queue<node> que; //创建node格式的队列
node st;
st.x=st.y=0; //从左上角出发
que.push(st);
vis[0][0]=1; //标记起点已经被走过
while(!que.empty()){ //如果队列不为空
node now=que.front(); //取队头
que.pop(); //出队
if(now.x==4&&now.y==4) //如果到达终点,结束
return;
for(int i=0;i<4;i++){ //向4个方向扩展
node next; //新建node型结构
next.x=now.x+dir[i][0];
next.y=now.y+dir[i][1];
if(next.x>=0&&next.x<5&&next.y>=0&&next.y<5&&!mp[next.x][next.y]&&!vis[next.x][next.y]){ //边界检查,墙体检查,路径检查
vis[next.x][next.y]=1;
que.push(next); //入队
pre[next.x][next.y]=now; //
}
}
}
}
void print(node cur){
if(cur.x==0&&cur.y==0){
printf("(0, 0)\n");
return;
}
print(pre[cur.x][cur.y]);//逆序输出(递归)
printf("(%d, %d)\n",cur.x,cur.y);
}
输入:
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出:
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
城市之间的油价是不同的,编写程序,寻找最便宜的城市间旅行方式。在旅行途中可以加满油箱。假设汽车每单位距离使用以单位燃料,从一个空油箱开始。
输入:输入的第1行包含 n n n( 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1≤n≤1000)和m( 0 ≤ m ≤ 10000 0 \leq m \leq 10000 0≤m≤10000),表示城市和道路的数量。下一行包含n个整数 p i p_{i} pi( 1 ≤ p i ≤ 100 1 \leq p_{i} \leq 100 1≤pi≤100),其中 p i p_{i} pi表示第 i i i个城市的燃油价格。接下来的 m m m行,每行都包含3个整数 u u u、 v v v( 0 ≤ u 0 \leq u 0≤u)和 d d d,表示在 u u u和 v v v之间有一条路,长度为 d d d。接下来一行是查询数 q q q( 1 ≤ q ≤ 100 1 \leq q \leq 100 1≤q≤100)。再接下来的 q q q行,每行都包含3个整数 c c c( 1 ≤ c ≤ 100 1 \leq c \leq 100 1≤c≤100)、 s s s和 e e e,其中 c c c是车辆的油箱容量, s s s是起点城市, e e e是终点城市。
输出:对于每个查询,都输出给定容量的汽车从 s s s到 e e e的最便宜旅程的价格,如果无法从 s s s到 e e e,则输出“impossible”
vis[u][vol] = 1
。vol+1
未扩展,则将该节点(u,vol+1,cost+price[u])
入队。vol-w
未扩展,则将该节点(v,vol-w,cost)
入队#include //加dp[][]优化
#include
#include
#include
using namespace std;
const int maxn=1005;
const int maxm=20005;
struct edge{
int v,w,next;
}edge[maxm];
struct node{
int u,vol,cost;
node(int u_,int vol_,int cost_){u=u_,vol=vol_,cost=cost_;}
bool operator < (const node &a) const{
return cost>a.cost;
}
};
int head[maxn];
bool vis[maxn][105];
int dp[maxn][105];//dp[i][j]表示在顶点i,当前油量为j时的最小花费。
int n,m,V,st,ed,cnt,price[maxn];
void add(int u,int v,int w){
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int bfs(){
memset(vis,0,sizeof(vis));
memset(dp,0x3f,sizeof(dp));
priority_queue<node>Q;
Q.push(node(st,0,0));
dp[st][0]=0;
while(!Q.empty()){
node cur=Q.top();
Q.pop();
int u=cur.u,vol=cur.vol,cost=cur.cost;
vis[u][vol]=1;
if(u==ed) return cost;
if(vol<V&&!vis[u][vol+1]&&dp[u][vol]+price[u]<dp[u][vol+1]){
dp[u][vol+1]=dp[u][vol]+price[u];
Q.push(node(u,vol+1,cost+price[u]));
}
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v,w=edge[i].w;
if(vol>=w&&!vis[v][vol-w]&&cost<dp[v][vol-w]){
dp[v][vol-w]=cost;
Q.push(node(v,vol-w,cost));
}
}
}
return -1;
}
int main(){
int u,v,w;
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<n;i++) scanf("%d",&price[i]);
cnt=0;
memset(head,-1,sizeof(head));
while(m--){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
int q;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&V,&st,&ed);
int ans=bfs();
if(ans==-1) puts("impossible");
else printf("%d\n", ans);
}
}
return 0;
}
输入:
5 5
10 10 20 12 13
0 1 9
0 2 8
1 2 1
1 3 11
2 3 7
2
10 0 3
20 1 4
输出:
170
impossible