洛谷 P1983 车站分级

这是一道存图+拓扑排序的题,但是看了一晚上好像只看出存图来....

 

 

下面说一下自己的理解的思路:

 

首先对这个题要有正确的理解:  

1.  给出的一趟车,它所停靠的站点一定 >= 它所经过站点中级别最小的点一定 >= 起始点和终点;

2.  所有停靠的点的级别一定 > 未停靠的点;

3.  根据大于关系建立有向无环图(DAG) ,拓扑排序

 

 

所以,这道题的鬼畜之一在于——建图:

不是将火车停靠的车站与下一个停靠车站之间建图,而是将没停靠的站点与其下一个停靠的车站构造一个有向无环图(因为没停靠的车站的级别一定比停靠的车站的级别要低...

 

这道题的鬼畜之二在于一个优化:

实际上有最坏的情况,就是两个点之间连了很多条边(因为有很多趟车,不同趟的车可能经过相同的站点),容易炸空间,所以就用vis数组进行标记,来简化空间复杂度.....

 

所以,这道题的思路可分为:

 

优化读入----->建图+vis优化------>拓扑排序-------->输出答案

 

下面是AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 
 5 using namespace std;
 6 
 7 inline int get_num() {//读入优化 
 8     int num = 0;
 9     char c = getchar();
10     while (c < '0' || c > '9') c = getchar();
11     while (c >= '0' && c <= '9')
12         num = num * 10 + c - '0', c = getchar();
13     return num;
14 }
15 
16 const int maxn = 1005;
17 
18 int graph[maxn][maxn], ind[maxn], stop[maxn], vis[maxn], level[maxn];
19 //graph存图,ind存点的入度,stop存车站,vis是否访问(一个优化),level存车站的级别 
20 queue<int> q;
21 
22 int main() {
23     int n = get_num(), m = get_num(), ans = 0;
24     for (int i = 1; i <= m; ++i) {
25         int s = 0, t = 0, cnt = get_num();
26         memset(stop, 0, sizeof(stop));
27         memset(vis, 0, sizeof(vis));
28         for (int j = 1; j <= cnt; ++j) {
29             if (j == 1) vis[s = stop[j] = get_num()] = 1;//起点车站 
30             else if (j == cnt) vis[t = stop[j] = get_num()] = 1;//终点车站 
31             else vis[stop[j] = get_num()] = 1;//一般车站 
32         } 
33         for (int j = 1; j <= cnt; ++j) { 
34             for (int k = s; k <= t; ++k)
35                 if (!vis[k] && !graph[k][stop[j]])//k车站没经过并且还没与车站j连成图 
36                     graph[k][stop[j]] = 1, ++ind[stop[j]];//构建有向无环图,j站入度+1 
37         }
38     }
39     for (int i = 1; i <= n; ++i)
40         if (!ind[i]) { //没有入度
41             level[i] = 1;//将级别设为1 
42             q.push(i);//入队,准备拓扑排序 
43         }
44     while (!q.empty()) {
45         int u = q.front();//取队首 
46         q.pop();
47         for (int v = 1; v <= n; ++v)//遍历 
48             if (graph[u][v]) {//如果u点与v点有一条边 
49                 if (level[v] < level[u] + 1)
50                     level[v] = level[u] + 1;//更新操作,因为所要到达的车站一定比前面那个没有到达的车站的级别要高 
51                 if (!(--ind[v])) q.push(v);//toposort核心(判断入度,并入队 
52             }
53         if (ans < level[u]) ans = level[u];//更新答案
54     }
55     printf("%d", ans);
56     return 0;
57 }

 

 

难点在于建图,真搞不懂是如何想到这样建图的!!!

 

toposort也很重要!!!

 

posted @ 2019-03-09 21:36  dfydn  阅读(355)  评论(1编辑  收藏  举报