题—送外卖2(最短路径&&dfs)

送外卖2

图论,动态规划,BFS,弗洛里德算法

感悟
1.dfs是个好东西,但是要优化喔
2.弗洛里德算法(简单的图,简单粗暴点直接三重for循环)
3.动态规划中的(一个数存取一长串二进制数,)二进制,
对二进制的移位,存取有了新的认识。
dp 拿以前的得到的结果,影响现在或者以后的结果。
4.思考用bfs的想法,实现实际是dfs.

bfs void(){ rep(i,1,q){
fla =1 bfs() fla()0;
}
rep(i,1,q){
w[i]=1; flg[i]=0; bfs; w[i]=0; flg[i]=1;
} }
在这里插入图片描述
多理解理解。
ps: 2号代码(用的是动态规划和二进制,想法很新颖)下次一定(doge);

牛客网:送外卖2 题意
n个点,m条有向边,q个外卖点。
q个外卖点信息 卖家位置,顾客位置,卖家做好的时间,顾客要求的时间送达
不管时间,问能送达的最大的外卖的点数。

1-------------------代码如下:
使用BFS解决
2020.11.11 优化后的代码
由割点(tarja算法)的启发,对dfs有了深刻的见解。
自己写的,害,dfs太爱了
下面为别人代码。

#include<iostream>
#include<cstring>
using namespace std;
int read(){
    int s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * f;
}

int n,m,q;
int a[100][100]; //i-j value 
//int flo[100][100]; // i-j minvalue
int flg[100];   //取与未取 
int w[100];   //完成与未完成
int sum;
struct zw {
	int u,v,t1,t2;
}d[100];
void bfs(int t,int num,int s){   //时间,完成送达数,当前状态的起点
	//for(int i=0;i<q;i++) cout<<flg[i]<<" ";
	//cout<<endl;
	sum=max(num,sum);
	//第一个for循环  完成快递员取到一些外卖 
	//三个主要步骤fla[i]=1 bfs fla[i]=0. 时间复杂度嘛q<=10,算友好
	//而且先后顺序也安排好了,如:可送第 1,3,4配送需求,位置变换(3,1,4...)也可以实现。
	// 如果i=1了,含第0号配送需求且第1个完成的可能性全都考虑完了。这就是这个for循环的含义.
	for(int i=0;i<q;i++){
		if(flg[i]||w[i])   continue;//
		int ts=max(t+a[s][d[i].u],d[i].t1);
		flg[i]=1;
		//目的:缩短时间.有些配送需求明显超时或到达不了,不执行bfs,缩短时间.
		int r=d[i].t2;
		for(int j=0;j<q;j++){
			if(d[j].t2<r&&flg[j]==1){
				r=d[j].t2;
			} 
		}   
		if(ts<=r)
		bfs(ts,num,d[i].u);
		flg[i]=0;
	     //flg[] 很多状态 一旦变了状态(由flg,w数组,确定状态)就是下一个状态,那么BFS 
		//BFS后 回到原来状态
	}
	//第二个循环  完成快递员将外卖送到用户手中. 思想同上一个for循环.
	//两个分立又关联的for循环,怎么完成任务呢:送第 1,3,4配送需求,一种情况两个for循环先后执行.
	for(int i=0;i<q;i++){
		if(w[i]||!flg[i]) continue;
		if(t+a[s][d[i].v]<=d[i].t2){
			w[i]=1;
			flg[i]=0;
			bfs(t+a[s][d[i].v],num+1,d[i].v);
			w[i]=0;
			flg[i]=1;
		}
	}
	return ;
} 
int main (){
	cin>>n>>m>>q;
	int u,v,value;
	memset(a,10000,sizeof(a));
	for(int i=1;i<=100;i++) a[i][i]=0;
	for(int i=1;i<=m;i++){
		u=read();v=read(); value=read();
		a[u][v]=min(value,a[u][v]);
	}
	cout<<a[1][4]<<"  "<<a[3][1]<<endl<<endl;
	//flyod
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;k++){
				if(a[j][k]>a[j][i]+a[i][k])
				  a[j][k]=a[j][i]+a[i][k];
			}
		}
	}
	//cout<<a[1][4]<<endl;
	for(int i=0;i<q;i++){
		d[i].u=read();d[i].v=read();
		d[i].t1=read();d[i].t2=read();
	}
	
	bfs(0,0,1);
   cout<<sum<<endl;	
} 

2--------------------代码如下:
使用动态规划解决:

#include<iostream>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int INF=0x3f3f3f3f;
int n,m,q;
int three[20]; //value:3的i次方
int dp[60000][30]; //当前完成的任务, 快递员当前所在点。
int digit[60000][30]; //所有的可能, 每种可能对应的三进制。
int a[410][410];
struct s_node{
	int from,to,l,r;
}b[600];
void floyd(){
	rep(i,1,n)
	 rep(j,1,n)
	  rep(k,1,n){
	  	a[j][k] = min(a[j][k],a[j][i]+a[i][k]);
	  }
	  return ;
}
void zw(){
	three[0] =1;
	for(int i=1;i<=10;i++)
	 three[i] = three[i-1]*3;
	 for(int i=0;i<three[10];i++){
	 	int ans=i;
	 	for(int j=0;j<10;j++){
	 		 digit[i][j]=ans%3;
	 		 ans/=3;
		 }
	 }
	 rep(i,0,60000-1)
	  rep(j,0,20)
	    dp[i][j]=INF;
	 rep(i,1,20){
	 	rep(j,1,20){
	 		if(i==j) a[i][j]=0;
	 		else a[i][j]=INF;
		 }
	 }
	 return ;
}
int main (){
	 //cout<<0x3f;
	cin>>n>>m>>q;
	zw();
	int x,y,value;
	for(int i=1;i<=m;i++){
		cin>>x>>y>>value;
		a[x][y]=min(value,a[x][y]);
	}
	floyd();
    rep(i,0,q-1){
    	cin>>b[i].from>>b[i].to>>b[i].l>>b[i].r;
	}
	int qs=1;
	rep(i,1,q) qs*=3;
	dp[0][1]=0;
	rep(i,0,qs-1){
	// 所有的点都试一遍
		rep(j,1,n){
			if(dp[i][j]<INF){
				rep(k,0,q-1){
					if(digit[i][k]==0){
						int next=i+three[k];
						int temp;
						temp=max(b[k].l,dp[i][j]+a[j][b[k].from]);
						dp[next][b[k].from]=min(dp[next][b[k].from],temp);
					}
					else if(digit[i][k]==1){
						int next=i+three[k];
						if(dp[i][j]+a[j][b[k].to]<=b[k].r){
							dp[next][b[k].to] = min(dp[next][b[k].to],dp[i][j]+a[j][b[k].to]);
						}
					}
					else continue;
				}
			}
		}
	}
	int ans=0;
	rep(i,0,qs-1){
		rep(j,1,n){
			if(dp[i][j]<INF){
				int num =0;
				//cout<<i<<endl;
				for(int k=0;k<q;k++){
					if(digit[i][k]==2) num++;
					
				}
				ans=max(ans,num);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

axtices

谢谢您的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值