题意
一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站。每个火车站都有一个级别,最低为 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。
(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是 5 趟车次的运行情况。其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求。
现有 m 趟车次的运行情况(全部满足要求),试推算这 n 个火车站至少分为几个不同的级别。
[Solution]
这题可以根据车分级,也可以根据点分级,写起来都差不多
(只是根据车分级跑的快,根据点分级跑得慢……)
先考虑点:
先说如何分级:如果两个点(A和B)被同一辆车经过,并且车停在了A,没有停在B,那么A的等级一定比B高.
那么根据这个,把等级高的向等级低的连一条边,表示它们不能在同一个等级.这个做法还是很好实现的,而且代码也很短.只需在读入时记录停留的点和没停留的点,把停留的点向所有没停留的点连一条边就好了.
这就是根据点分级的做法了,只要算出不同等级的数量,就得到了答案
然后就是怎么求的问题了,很容易发现,构造出的图一定是一个有向无环图(DAG),所以当然是选择dp求了.每个点的等级都是所有儿子中的最大值加1.
由于数据很水,这种方法卡下常数就过了…..
如果有了点的做法,其实车的做法也很接近了:
把车的等级定为这辆车上等级最低的点.对于两辆车(A,B),假如它们的路线相交,在相交路径上停靠点少的车的等级比另一辆高.这样车也有等级了,然后把车当成点,再按点的算法计算就好了.
但是这样好像不对,车的等级为什么能代表点的等级呢?
A车的等级为2,B为1.但是它们上面都有和它们等级不同的点;不过,这也没关系,因为取了这辆车中等级最高的点,所以不用关心其它点.
(但是必须再加一辆从1到n停靠所有点的车,保证没有点的等级为0
这样的话和上一种其实差不多,但是,车之间比较大小只需要用前缀和维护区间和,就可以让比较大小的复杂度变为 O(1) ,但是点之间比较大小的复杂度必须要 O(n)
所以,想到一种不怎么样的算法后,再仔细想想,可能就想出整解了
#include
#include
#include
#include
using namespace std;
const int M=1005;
struct node {
int st,ed;
int sum[M];
bool operator > (const node &t) const {
int mst=max(st,t.st);
int med=min(ed,t.ed);
if (mst>med) return false;
return sum[med]-sum[mst-1]>t.sum[med]-t.sum[mst-1];
}
} way[M];
vector <int> e[M];
int dp[M];
int rec(int x) {
if (dp[x]) return dp[x];
int res=0;
for (int i=0;ireturn dp[x]=res+1;
}
int main() {
int n,m;
cin>>n>>m;
for (int i=1;i<=m;++i) {
int s;
scanf("%d",&s);
for (int j=1;j<=s;++j) {
int x;
scanf("%d",&x);
if (j==1) way[i].st=x;
else if (j==s) way[i].ed=x;
way[i].sum[x]=1;
}
for (int j=way[i].st;j<=way[i].ed;++j) way[i].sum[j]+=way[i].sum[j-1];
}
way[0].st=0,way[0].ed=n;
for (int i=1;i<=n;++i) way[0].sum[i]=way[0].sum[i-1]+1;
for (int i=0;i<=m;++i) {
for (int j=0;j<=m;++j) {
if (i==j) continue;
if (way[i]>way[j]) e[i].push_back(j);
}
}
int res=0;
for (int i=0;i<=m;++i) {
res=max(res,rec(i));
}
cout<return 0;
}