L2-1. 紧急救援
时间限制200 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者陈越作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出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
这题是一题求最短路的题目,但是还要求不同路径的条数,所以想到用dfs 回朔法,中间要剪枝,已提升速度,并且记录路径;
但是 如果只用dfs回朔剪枝回发现最后一个测试点通不过,超时了,速度还要优化;
这就想到,先用dijkstra先求一下到终点距离以内的最短路,以外的就不管了,而且通过标记数组temp排除他们;
再把每个点最短距离拿去dfs剪枝,速度就提升上来了;
#include<iostream> #include<stack> #include<vector> #include<queue> #include<stdio.h> using namespace std; int n, m, s, d; int **city; int temp[500];//记录这个点有没有被访问过,在dfs中为1则不用访问.dijkstra为0不用访问; int people[500];//存放每个城市救援队数量; int path[500] = { 0 };//用来记录路径,path[i]代表i点前面一个点; int pp = 0, dd = 0;//pp是现在救援队数量,dd是目前走的距离,在dfs中用到; int mini = 99999;//起点到终点最短距离; int maxx = 0;//最大救援队数量 int num = 0; int diss[500];//存放s到i点最短路长度的数组; stack<int> sta;//用来记录路径的栈 int dfs(int x){ if (x == d){ if (dd == mini&&pp < maxx) num++; else{ if (dd == mini)num++; else num = 1; while (!sta.empty())sta.pop(); mini = dd; maxx = pp; for (int i = d; i != s; i = path[i]) sta.push(i); sta.push(s); return 1; } } temp[x] = 1; for (int i = 0; i < n; i++) { if (city[i][x] >= 0 && !temp[i] && dd + city[i][x] <= diss[i]) { path[i] = x; dd += city[i][x], pp += people[i]; dfs(i); dd -= city[i][x], pp -= people[i]; } } temp[x] = 0; return 1; } class node{ public:int c; int dis; bool operator <(const node a)const{ return dis>a.dis; } };//优先队列用到的node结点 int dijkstra(int s){ priority_queue <node> q; for(int i=0;i<n;i++) temp[i]=1,diss[i]=99999; diss[s]=0; node n1,n2; n1.c=s; n1.dis=0; q.push(n1); temp[s]=0; while(!q.empty()){ n1=q.top(); q.pop(); temp[n1.c]=0; if(n1.c==d) return n1.dis; for(int i=0;i<n;i++) if(temp[i]&&city[n1.c][i]>=0&&diss[i]>diss[n1.c]+city[n1.c][i]) {n2.dis=diss[n1.c]+city[n1.c][i],n2.c=i; q.push(n2); diss[i]=diss[n1.c]+city[n1.c][i]; } } } int main(){ //freopen("F:\\1.txt","r",stdin); cin >> n >> m >> s >> d; city = new int*[n]; for (int i = 0; i < n; i++) { city[i] = new int[n]; for (int j = 0; j < n; j++) city[i][j] = -9999; } for (int i = 0; i < n; i++) cin >> people[i]; for (int i = 0; i < m; i++) { int x, y, w; cin >> x >> y >> w; city[x][y] = w; city[y][x] = w; } pp = people[s]; mini=dijkstra(s);//算得到终点的最短路长度;并且记录下每个最短路范围内,每个点最短路长度; dfs(s);//用dfs,并且回朔剪枝 ,求路的条数和最大救援数; cout << num << " " << maxx << endl; if (!sta.empty()) cout << sta.top(), sta.pop(); while (!sta.empty()) { cout << " " << sta.top(); sta.pop(); } //fclose(stdin); }