PAT _(刷题4) 图-重要 1111 Online Map (30分) 1131 Subway Map (30分) 1139 First Contact (30分)

目录

 

1111 Online Map (30分) (升级版 dijkstra+dfs)

1131 Subway Map (30分) (dfs *)

方法2: 

1139 First Contact (30分)


1111 Online Map (30分) (升级版 dijkstra+dfs)

另一篇

题⽬⼤意:给⼀张地图,两个结点中既有距离也有时间有的单⾏有的双向,要求根据地图推荐两条路线:⼀条是最快到达路线,⼀条是最短距离的路线。 第⼀⾏给出两个整数N M ,表示地图中地点的个数和路径的条数。接下来的 M ⾏每⼀⾏给出:道路结点编号V1 道路结点编号 V2 是否单⾏线 道路⻓度 所需时间
 
要求,第一⾏输出最短距离Distance和路径,第二⾏输出最快到达时间Time和路径
分析:
1.⽤两个Dijkstra。⼀个求最短路径(如果相同求时间最短的那条),⼀个求最快路径(如果相同求结 点数最⼩的那条)
2. 求最短路径 , 和最快路径都可以在 Dijkstra ⾥⾯求前驱结点  dispre和,Timepre 数组
3 .dispre数组更新的条件是路径更短,或者路径相等的同时时间更短 (同A1003 Emergency (25分)
4. 求最快路径时候要多维护⼀个NodeNum数组,记录在时间最短的情况下,到达此节点所需的节点数量
 
Time 数组更新的条件是,时间更短,时间相同的时候,如果此节点能让到达此节点是数⽬也变⼩,则更新Timepre ,和 NodeNum 数组
5. 最后根据dispre Timepre数组递归出两条路径,⽐较判断,输出最终答案~
注意:如果直接使⽤ DFS 的话,会导致最后⼀个测试⽤例 运⾏超时

 

#include 
#include 
#include 
using namespace std;
const int inf = 999999999;
int dis[510], Time[510], e[510][510], w[510][510], dispre[510],Timepre[510], weight[510],NodeNum[510];
bool visit[510];
vector dispath, Timepath, temppath;
int st, fin, minnode = inf;
void dfsdispath(int v) {
    dispath.push_back(v);
    if(v == st) return ;
    dfsdispath(dispre[v]);
}
void dfsTimepath(int v) {
    Timepath.push_back(v);
    if(v == st) return ;
    dfsTimepath(Timepre[v]);
}
int main() {
    fill(dis, dis + 510, inf);
    fill(Time, Time + 510, inf);
    fill(weight, weight + 510, inf);
    fill(e[0], e[0] + 510 * 510, inf);
    fill(w[0], w[0] + 510 * 510, inf);
    int n, m;
    scanf("%d %d", &n, &m);
    int a, b, flag, len, t;
    for(int i = 0; i < m; i++) {
        scanf("%d %d %d %d %d", &a, &b, &flag, &len, &t);
        e[a][b] = len;
        w[a][b] = t;
        if(flag != 1) {
            e[b][a] = len;
            w[b][a] = t;
        }
    }
    scanf("%d %d", &st, &fin);
    dis[st] = 0;
    for(int i = 0; i < n; i++)
        dispre[i] = i;
    for(int i = 0; i < n; i++) {
        int u = -1, minn = inf;
        for(int j = 0; j < n; j++) {
            if(visit[j] == false && dis[j] < minn) {
                u = j;
                minn = dis[j];
            }
        }
        if(u == -1) break;
        visit[u] = true;
        for(int v = 0; v < n; v++) {
            if(visit[v] == false && e[u][v] != inf) {
                if(e[u][v] + dis[u] < dis[v]) {
                    dis[v] = e[u][v] + dis[u];
                    dispre[v] = u;
                    weight[v] = weight[u] + w[u][v];
                } else if(e[u][v] + dis[u] == dis[v] && weight[v] > weight[u] + w[u][v]) {
                    weight[v] = weight[u] + w[u][v];
                    dispre[v] = u;
                }
            }
        }
    }
    dfsdispath(fin);
    Time[st] = 0;
    fill(visit, visit + 510, false);
    for(int i = 0; i < n; i++) {
        int u = -1, minn = inf;
        for(int j = 0; j < n; j++) {
            if(visit[j] == false && minn > Time[j]) {
                u = j;
                minn = Time[j];
            }
        }
        if(u == -1) break;
        visit[u] = true;
        for(int v = 0; v < n; v++) {
            if(visit[v] == false && w[u][v] != inf) {
                if(w[u][v] + Time[u] < Time[v]) {
                    Time[v] = w[u][v] + Time[u];
                    Timepre[v]= u;
                    NodeNum[v]=NodeNum[u]+1;
                } else if(w[u][v] + Time[u] == Time[v]&&NodeNum[u]+1= 0; i--) {
            printf("%d", dispath[i]);
            if(i != 0) printf(" -> ");
        }
        printf("\nTime = %d: ", Time[fin]);
    }
    for(int i = Timepath.size() - 1; i >= 0; i--) {
        printf("%d", Timepath[i]);
        if(i != 0) printf(" -> ");
    }
    return 0;
}

 

 

1112 1133 1136  1137 1141

 

1131 Subway Map (30分) (dfs *)

题目大意:找出一条路线,使得对任何给定的起点和终点,可以找出中途经停站最少的路线;如果经停站一样多,则取需要换乘线路次数最少的路线
分析: 一遍DFS即可~DFS过程中要维护两个变量:minCnt-中途经停的最少的站; minTransfer-需要换乘的最小次数~
0.可以这样计算出一条线路的换乘次数:用line[10000][10000]的数组 或者(unordered_map line)保存每两个相邻站中间的线路是几号线~从头到尾遍历最终保存的路径,preLine为前一小段的线路编号如果当前的结点和前一个结点组成的这条路的线路编号和preLine不同,说明有一个换乘,就将cnt+1,最后遍历完累加的cnt即是换乘的次数~
1.可以这样计算出一条线路中途停站的次数:在dfs的时候有个变量cnt,表示当前路线是所需乘的第几个站,每次dfs时候将cnt+1表示向下遍历一层~cnt就是当前中途停站的次数~

2.可以这样输出结果:和计算线路换乘次数的思路一样,每当preLine和当前Line值不同的时候就输出一句话~保存preTransfer表示上一个换乘站,最后不要忘记输出preTransfer和最后一个站之间的路即使最后一个站并不是换乘站

 

#include 
#include 
#include 
using namespace std;
vector> v(10000);
int visit[10000], minCnt, minTransfer, start, end1;
unordered_map line;
vector path, tempPath;
int transferCnt(vector a) { //计算路径上的换乘站数
    int cnt = -1, preLine = 0;
    for (int i = 1; i < a.size(); i++) {
        if (line[a[i-1]*10000+a[i]] != preLine) cnt++;
        preLine = line[a[i-1]*10000+a[i]];
    }
    return cnt;
}
void dfs(int node, int cnt) {
    if (node == end1 && (cnt < minCnt || (cnt == minCnt && transferCnt(tempPath) < minTransfer))) {
        minCnt = cnt;
        minTransfer = transferCnt(tempPath);
        path = tempPath;
    }
    if (node == end1) return;
    for (int i = 0; i < v[node].size(); i++) {
        if (visit[v[node][i]] == 0) {
            visit[v[node][i]] = 1;
            tempPath.push_back(v[node][i]);
            dfs(v[node][i], cnt + 1);
            visit[v[node][i]] = 0;
            tempPath.pop_back();
        }
    }
}
int main() {
    int n, m, k, pre, temp;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d%d", &m, &pre);
        for (int j = 1; j < m; j++) {
            scanf("%d", &temp);
            v[pre].push_back(temp);
            v[temp].push_back(pre);
            line[pre*10000+temp] = line[temp*10000+pre] = i + 1;
            pre = temp;
        }
    }
    scanf("%d", &k);
    for (int i = 0; i < k; i++) {
        scanf("%d%d", &start, &end1);
        minCnt = 99999, minTransfer = 99999;
        tempPath.clear();
        tempPath.push_back(start);
        visit[start] = 1;
        dfs(start, 0);
        visit[start] = 0;
        printf("%d\n", minCnt);
        int preLine = 0, preTransfer = start;
        for (int j = 1; j < path.size(); j++) {
            if (line[path[j-1]*10000+path[j]] != preLine) {
                if (preLine != 0) printf("Take Line#%d from %04d to %04d.\n", preLine, preTransfer, path[j-1]);
                preLine = line[path[j-1]*10000+path[j]];
                preTransfer = path[j-1];
            }
        }
        printf("Take Line#%d from %04d to %04d.\n", preLine, preTransfer, end1);
    }
    return 0;
}

方法2: 

#include
#include
#include 
using namespace std;
struct station{
	 int to, line;
}sta;
struct PATH{
	 int s ,e ,line; 
}path; 
vector< vector< station > > v(20000);
vector< struct PATH > ans,ans1;
int  vis[10009] ,pres,prel ,minn=99999,mint=99999;
void dfs( int s , int e , int cnt , int takes ){ 
	 if( cnt > minn )
	   return ;
	 if( s == e ){
	 	 ans.push_back( path={ pres , s ,prel} );
	 	 if( cnt  >n; 
    for( int i=1;i<=n;i++){
	   cin>>num>>t1; 
	   for( int j=2;j<=num;j++){
	   	    cin>>t2;
	   	    v[t1].push_back( sta={t2,i} );
	   	    v[t2].push_back( sta={t1,i} );
	   	    t1=t2; 
	   }   
	}
	int k,s,e;
	cin>>k;
	for(int i=1;i<=k;i++){
	    cin>>s>>e; 
	    pres = s; 
	    prel = -1;
	    minn=99999,mint=99999;
	    fill(vis,vis+10009,0);
	    ans.clear();
	    ans1.clear();
	    vis[s] = 1;
		dfs(s,e,0,0); 
		cout<

1139 First Contact (30分)(unordered_map arr)

unordered_map arr  存图 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define pii pair
using namespace std;
const int maxn=100005;
int n,m,k;
unordered_map mp; ///图 mp[0001*10000+0002]=1 代表0001->0002
bool cmp(pii a,pii b){
    return a.first!=b.first?a.first>n>>m;
	string a,b;
	vector v[10000];
	int ta,tb;
	for(int i=0;i>a>>b;
		ta=abs(stoi(a)); tb=abs(stoi(b));
		if(a.length()==b.length()){
            v[ta].pb(tb);
            v[tb].pb(ta);
		}
		mp[ta*10000+tb]=mp[tb*10000+ta]=1;
	}
	cin>>k;
	int tmpa,tmpb,c,d;
	string start,des;
	vector ans;
	while(k--){
        ans.clear();
        cin>>start>>des;
        tmpa=abs(stoi(start)); tmpb=abs(stoi(des));
        for(int i=0;i

 

你可能感兴趣的:(pat,dfs,算法,数据结构)