PAT甲级1131.

目录

A1131

题目

样例

输入:

4
7 1001 3212 1003 1204 1005 1306 7797
9 9988 2333 1204 2006 2005 2004 2003 2302 2001
13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
4 6666 8432 4011 1306
3
3011 3013
6666 2001
2004 3001

输出:

2
Take Line#3 from 3011 to 3013.
10
Take Line#4 from 6666 to 1306.
Take Line#3 from 1306 to 2302.
Take Line#2 from 2302 to 2001.
6
Take Line#2 from 2004 to 1204.
Take Line#1 from 1204 to 1306.
Take Line#3 from 1306 to 3001.

思路和坑点

  代码年代久远了,我记得是参考了柳神的代码,这题挺难了,看懂了自己也不一定能独立写得出来。

AC代码

#include<bits/stdc++.h>
using namespace std; 
vector<int> v[10000];
bool vis[10000]={false};                        //占用标记
int mincnt,minTrans,st,ed;                    
unordered_map<int,int> line;
vector<int> path,temppath;
int transfercnt(vector<int> &a){                //换乘统计 
    int cnt=-1,preline=0;                       //cnt计数,preline前一段的路线编号 
    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){                     //dfs
    if(node==ed){                               //如果到大终点          
        if(cnt<mincnt){                         //如果路径更短。更新 
            mincnt=cnt;
            minTrans=transfercnt(temppath);
            path=temppath;
        }
        else if(cnt==mincnt&&transfercnt(temppath)<minTrans){//如果长度相同,但是换乘更少,也更新 
            mincnt=cnt;
            minTrans=transfercnt(temppath);
            path=temppath;
        }
        return;
    }
    for(int i=0;i<v[node].size();i++){          //递归的dfs搜索node相邻接的顶点 
        int k=v[node][i];
        if(vis[k]==false){
            vis[k]=true;                        //计入路径,并修改标记 
            temppath.push_back(k);        
            dfs(k,cnt+1);        
            vis[k]=false;                       //解除占用 
            temppath.pop_back();                //回上一层 
        }
    }     
}
int main(){    
#ifdef ONLINE_JUDGE    
#else    
    freopen("1.txt", "r", stdin);    
#endif    
    int n,m,k,pre,temp;
    scanf("%d",&n);
    for(int i=1;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;
            pre=temp;
        }
    }
    scanf("%d",&k);
    for(int i=0;i<k;i++){
        scanf("%d%d",&st,&ed);
        mincnt=99999,minTrans=99999;            //初始化统计变量 
        temppath.clear();                       //其实顶点放入路径 
        vis[st]=true;                           //修改标记 
        temppath.push_back(st);
        dfs(st,0);
        vis[st]=false;                          //解除占用,还原状态 
        printf("%d\n",mincnt);
        int preline=0,pretrans=st;
        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,pretrans,path[j-1]);
                preline=line[path[j-1]*10000+path[j]];
                pretrans=path[j-1];
            }
        }
        printf("Take Line#%d from %04d to %04d.\n",preline,pretrans,ed);
    } 
    return 0;    
}