作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3
代码长度限制 16 KB
时间限制 200 ms
内存限制 64 MB
栈限制 8192 KB
也是一道经典pta的l2阶段的题了,这道题关键是求出所有的最短路径的条数,本人比较菜刚开始没有想出来怎么实现,试着用dfs+剪枝看看呢不能蹭过,结果发现最后一个测试点死活过不去,又想到了用并查集记录一下哪个点能到达终点,但是只快了1ms,最后一个测试点死活过不去。
附上代码:
#include <bits/stdc++.h>
using namespace std;
struct edge{
int from,to;
long long int w;
edge(int a,int b,long long int c) {from=a;to=b;w=c;}
};
vector <edge> e[505];
long long int ab_w[505][505];
vector <int> path;
vector <int> ans;
long long int path_len=1e15;
long long int path_sum=0;
int path_cnt=0;
bool book[505];
int jiu[505];
int fu[505];
bool is_dao[505];
int n,m,s,d;
int find_fu(int x)
{
if( fu[x]==x ) return x;
return fu[x]=find_fu(fu[x]);
}
void dfs(int now)
{
if(now==d)
{
long long int len=0;
for(int i=0;i<path.size();i++)
{
//cout<<path[i]<<' ';
if(i<path.size()-1) len+=ab_w[ path[i] ][ path[i+1] ];
}
//cout<<'\n';
if(len<path_len)
{
path_cnt=1;
path_len=len;
long long int sum=0;
for(int i=0;i<path.size();i++)
{
sum+=jiu[ path[i] ];
}
path_sum=sum;
ans.clear();
for(int i=0;i<path.size();i++)
{
ans.push_back(path[i]);
}
return;
}
if(len==path_len)
{
path_cnt++;
long long int sum=0;
for(int i=0;i<path.size();i++)
{
sum+=jiu[ path[i] ];
}
if(sum>path_sum)
{
path_sum=sum;
ans.clear();
for(int i=0;i<path.size();i++)
{
ans.push_back(path[i]);
}
}
return;
}
return;
}
if(is_dao[now]==0) return;
for(int i=0;i<e[now].size();i++)
{
if(book[ e[now][i].to ]==0)
{
path.push_back(e[now][i].to);
book[ e[now][i].to ]=1;
dfs(e[now][i].to);
path.pop_back();
book[ e[now][i].to ]=0;
}
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m>>s>>d;
for(int i=0;i<n;i++){e[i].clear();book[i]=0;fu[i]=i;}
for(int i=0;i<n;i++)
{
cin>>jiu[i];
}
for(int i=0;i<m;i++)
{
int a,b;long long int c;cin>>a>>b>>c;
e[a].push_back( edge(a,b,c) );
e[b].push_back( edge(b,a,c) );
ab_w[a][b]=c;
ab_w[b][a]=c;
if( find_fu(a)!=find_fu(b) ) fu[ find_fu(a) ]=find_fu(b);
}
for(int i=0;i<n;i++)
{
if( find_fu(i) == find_fu(d) ) is_dao[i]=1;
else is_dao[i]=0;
}
path.push_back(s);
book[s]=1;
dfs(s);
//cout<<'\n';
cout<<path_cnt<<' '<<path_sum<<'\n';
for(int i=0;i<ans.size();i++)
{
cout<<ans[i];
if(i!=ans.size()-1) cout<<' ';
}
return 0;
}
想到dij算法中,关键代码有一个比较 下一个节点到起点的最短距离 是不是小于 目前节点到起点的距离+目前节点到下一个几点的距离( dis[nex_id] > dis[now.id] + nex_w )
我们都知道,如果要打印路径,要用一个pre[ ]数组去存储每个结点的上一个节点,那么如果当(dis[nex_id] == dis[now.id] + nex_w)的时候,是不是可以存多个呢,用vector <int> pre[n]存储更加方便,这样就知道i节点的pre[i]有几个父节点。并且打印路径的时候要用到dfs的方法。
果然ac了,看来dfs即使剪枝也是太慢了。
附上代码:
#include <bits/stdc++.h>
using namespace std;
struct edge{
int from,to;
long long int w;
edge(int a,int b,long long int c) {from=a;to=b;w=c;}
};
struct node{
int id;
long long int i_to_d_dis;
node(int a,long long int b){id=a;i_to_d_dis=b;}
bool operator < (const node a) const
{
return i_to_d_dis>a.i_to_d_dis;
}
};
vector < edge > e[505];
long long int dis[505];
bool book[505];
int jiu[505];
vector <int> pre[505];
bool pre_book[505];
vector <int> path;
long long int ans_sum=0;
vector <int> ans;
int cnt=0;
int n,m,s,d;
void find_path(int now)
{
if(now==s)
{
cnt++;
long long int sum=0;
for(int i=path.size()-1;i>=0;i--)
{
//cout<<path[i]<<' ';
sum+=jiu[ path[i] ];
}
//cout<<" sum="<<sum<<'\n';
if(ans_sum<sum)
{
ans_sum=sum;
/*ans.clear();
for(int i=0;i<path.size();i++) ans.push_back(path[i]);*/
ans=path;
}
return;
}
for(int i=0;i<pre[now].size();i++)
{
if(pre_book[pre[now][i]]==0)
{
pre_book[pre[now][i]]=1;
path.push_back(pre[now][i]);
find_path(pre[now][i]);
path.pop_back();
pre_book[pre[now][i]]=0;
}
}
}
void dij()
{
dis[s]=0;
priority_queue <node> dui;
dui.push( node(s,dis[s]) );
while(dui.size()>0)
{
node now=dui.top();
dui.pop();
if(book[now.id]==1) continue;
book[now.id]=1;
for(int i=0;i<e[now.id].size();i++)
{
int nex_id=e[now.id][i].to;
long long int nex_w=e[now.id][i].w;
if(dis[nex_id] > dis[now.id] + nex_w )
{
dis[nex_id] = dis[now.id] + nex_w;
dui.push( node(nex_id,dis[nex_id]) );
pre[nex_id].clear();
pre[nex_id].push_back(now.id);
}
else if(dis[nex_id] == dis[now.id] + nex_w )
{
dui.push( node(nex_id,dis[nex_id]) );
pre[nex_id].push_back(now.id);
}
}
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m>>s>>d;
for(int i=0;i<n;i++){e[i].clear();book[i]=0;dis[i]=1e15;pre[i].clear();pre_book[i]=0;}
for(int i=0;i<n;i++)
{
cin>>jiu[i];
}
for(int i=0;i<m;i++)
{
int a,b;long long int c;cin>>a>>b>>c;
e[a].push_back( edge(a,b,c) );
e[b].push_back( edge(b,a,c) );
}
dij();
//
path.push_back(d);
pre_book[d]=1;
find_path(d);
//
/*for(int j=0;j<n;j++)
{
cout<<"节点"<<j<<"的前驱点为:";
for(int i=0;i<pre[j].size();i++) cout<<pre[j][i]<<'.';
cout<<'\n';
} */
cout<<cnt<<' '<<ans_sum<<'\n';
for(int i=ans.size()-1;i>=0;i--)
{
cout<<ans[i];
if(i>0) cout<<' ';
}
return 0;
}
178

被折叠的 条评论
为什么被折叠?



