pta--1003 Emergency / L2-001 紧急救援 (25 分)(dijkstra+dfs || dfs || bfs)

甲级1003 Emergency (25)(25 分)

L2-001 紧急救援 (25 分)

【题意】两道题题意是一样的,记录最短路径的数目和最多能够gather的人数。但是L2-001要输出路径;所以用dijkstra+dfs来做

【代码】注释掉是甲级的代码,没注释掉的话就是L2的了

#include<bits/stdc++.h>
using namespace std;

const int maxn=510;
const int inf=0x3f3f3f3f;
int e[maxn][maxn];
int dis[maxn];
int book[maxn];
int w[maxn];
vector<int>path[maxn];
vector<int>t,tt;

int n,m,st,ed;
int sum,maxnum;

void dijkstra(int x)
{
	memset(dis,inf,sizeof(dis));
	memset(book,0,sizeof(book));
	dis[x]=0;
	for(int i=0;i<n;++i)
	{
		int now=-1,minn=inf;
		for(int j=0;j<n;++j)
			if(!book[j] && minn>dis[j])
				minn=dis[j],now=j;
		if(now==-1)break;
		book[now]=1;
		for(int j=0;j<n;++j)
		{
			if(!book[j])
			{
				if(dis[j]>dis[now]+e[now][j])
				{
					dis[j]=dis[now]+e[now][j];
					path[j].clear();
					path[j].push_back(now);
				}
				else if(dis[j]==dis[now]+e[now][j])
					path[j].push_back(now);
			}
		}
	}
}
void dfs(int x)
{
	if(x==st)
	{
		sum++;
		t.push_back(x);
		int mans=0;
		for(int i=t.size()-1;i>=0;--i)
			mans+=w[t[i]];
		if(maxnum<mans)maxnum=mans,tt=t;
		t.pop_back();
		return;
	}
	t.push_back(x);
	for(int i=0;i<path[x].size();++i)
		dfs(path[x][i]);
	t.pop_back();
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&st,&ed);
	for(int i=0;i<n;++i)scanf("%d",&w[i]);
	memset(e,inf,sizeof(e));
	while(m--)
	{
		int a,b,d;scanf("%d%d%d",&a,&b,&d);
		e[a][b]=e[b][a]=d;
	}
	sum=0;maxnum=0;
	dijkstra(st);
	dfs(ed);
	printf("%d %d\n",sum,maxnum);
	for(int i=tt.size()-1;i>=0;--i)
		(i==0)?printf("%d\n",tt[i]):printf("%d ",tt[i]);
}

【注意】一般地,如果在回溯法中修改了辅助的全局变量,则一定要及时把它们恢复原状,除非要故意保留你的修改。

for(int i=0;i<n;i++)
{
	if(vis[i]||dis[city][i]==-1)
		continue;
	vis[i]=1;//修改
	dfs(i,length+dis[city][i],mans+man[i]);
	vis[i]=0;//这里恢复原状
}	

【DFS代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m,c1,c2,num=1,MM=0;
int vis[maxn];
int dis[maxn][maxn];
int man[maxn];
int minn=0x3f3f3f3f;
void dfs(int city,int length,int mans)
{
	if(city==c2)
	{
		if(length>minn)return;
		if(length==minn){
			num++;        //数目增加
			MM=max(mans,MM);//取最大的那个
		}
		else{
			num=1;    //数目归1
			MM=mans;
			minn=length;
		}
	//	cout<<MM<<endl;
	}
	if(length>minn)return;
	for(int i=0;i<n;i++)
	{
		if(vis[i]||dis[city][i]==-1)
			continue;
		vis[i]=1;
		dfs(i,length+dis[city][i],mans+man[i]);
		vis[i]=0;
	}	
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&c1,&c2);
	memset(man,0,sizeof(man));
	memset(dis,-1,sizeof(dis));
	for(int i=0;i<n;i++)
		scanf("%d",&man[i]);
	for(int i=0;i<m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		dis[x][y]=dis[y][x]=z;
	}
	memset(vis,0,sizeof(vis));
	dfs(c1,0,man[c1]);
	cout<<num<<" "<<MM<<endl;
}

【BFS代码】emmm大佬的代码,,要用优先队列,并且要标记。如果只求最短路径而不统计数目的话其实就不用标记也不用用到优先队列。但是这里是求数目,如果不标记的话同一个点重复走,这个点所连接的点也重复记录了,这时,数目就会不对。还有就是注意,

if ( vis[to] == (vis[x] + dis[x][to]) )
{
	sum[to] += sum[x];
	people[to] = max(people[to],people[x] + man[to]);
	q.push(to);
}

这里不是增加1,而是增加sum[x]。

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m,c1,c2,num=1,MM=0;
int vis[maxn];
int dis[maxn][maxn];
int man[maxn];
vector<int>f[maxn]; 
int sum[maxn],people[maxn];
int minn=0x3f3f3f3f;

struct cmp{
	bool operator()(int a, int b){
		return vis[a] > vis[b];
	}
};
int vvis[maxn];
void bfs(int city)
{
	memset(people,0,sizeof(people));
	memset(sum,0,sizeof(sum));
	memset(vis,0x3f3f3f3f,sizeof(vis));
	memset(vvis,0,sizeof(vvis));
	priority_queue<int,vector<int>,cmp>q;
	q.push(city);
	vis[city] = 0;
	people[city] = man[city];
	sum[city] = 1;
	while(!q.empty())
	{
		int x=q.top();q.pop();
		if (vvis[x]) continue;
		vvis[x] = 1;
		if (x == c2) continue;
		int len = f[x].size();
		for (int i = 0 ; i < len ; ++i)
		{
			int to = f[x][i];
			if ( vis[to] == (vis[x] + dis[x][to]) )
			{
				sum[to] += sum[x];
				people[to] = max(people[to],people[x] + man[to]);
				q.push(to);
			}
			else
			if ( vis[to] > (vis[x] + dis[x][to]) )
			{
				vis[to] = vis[x] + dis[x][to];
				sum[to] = sum[x];
				people[to] = people[x] + man[to]; 
				q.push(to);
			} 
		}	
	}
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&c1,&c2);
	for(int i=0;i<n;i++){
		scanf("%d",&man[i]);
		f[i].clear();
	}
	for(int i=0;i<m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		dis[x][y]=dis[y][x]=z;
		f[x].push_back(y);
		f[y].push_back(x);
	}
	bfs(c1);
	cout<<sum[c2]<<" "<<people[c2]<<endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值