【NOIP2013 普及组】车站分级
一、题目
【NOIP2013 普及组】车站分级
时间限制: 1 Sec 内存限制: 128 MB
提交: 3 解决: 0
[提交][状态][讨论版]
题目描述
一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站。每个火车站都有一个级别,最低为 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是 5 趟车次的运行情况。其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求。
现有 m 趟车次的运行情况(全部满足要求),试推算这 n 个火车站至少分为几个不同的级别。
输入
输入文件为 level.in。
第一行包含 2 个正整数 n, m,用一个空格隔开。
第 i + 1 行(1 ≤ i ≤ m)中,首先是一个正整数 si(2 ≤ si ≤ n),表示第 i 趟车次有 si 个停靠站;接下来有 si个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。
输出
输出文件为 level.out。
输出只有一行,包含一个正整数,即 n 个火车站最少划分的级别数。
样例输入
输入样例#1:
9 2
4 1 3 5 6
3 3 5 6
输入样例#2:
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
样例输出
输出样例#1:
2
输出样例#2:
3
提示
对于 20%的数据,1 ≤ n, m
≤ 10;
对于 50%的数据,1 ≤ n, m
≤ 100;
对于 100%的数据,1 ≤ n, m
≤ 1000。
二、分析及代码
首先考虑50%的数据,我们知道对于每一列车,它经过的站点中停了的站点的等级肯定比没停的站点高。因此对于每一辆车,我们可以把它经过的每一个没停的站点向每一个停了的站点建一条边。然后我们会得到一张图,在这张图上找最长的一条路段即可。
然后考虑正解,显然对于点考虑是无法再优化了,因此我们考虑车。我们定义一辆车的等级就是它经过站点的最小等级。我们考虑如何判定两辆车的等级大小。
对于两辆车,它们如果没有交点,那么它们的等级没有关系。
两辆车相交区间(都有停的区间)中,如果一辆车停的车辆多,那么它的等级低。
于是我们就建立了两辆车之间的大小关系,同样的,应用拓扑排序就可以找到这个最大的等级。
最后,还有一点要注意,因为我们处理的是车,而最后要求的是点。如果对于一辆等级为1的车,它经过的站点中如果有一个站点一辆车都没有停靠,那么最后的答案就要加1。
对于测试数据二:
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
比如第二辆车和第三辆车,都停了站5,但是第三辆车没有停3,所以第三辆车优先级比第二辆车高。
比如第一辆车和第二辆车的确有共同停靠站,且第一辆车停的站的确比第二辆车多,但是并不能说明第一辆车的等级低于第二辆车,因为起始站不同。
增加一辆每个站都停的列车,来作为等级最低的列车。
因为经过前面我们可以求出所有列车的等级,但是里面等级最低的一辆车要是有一个站没停,就存在着更低的一辆列车。这样才是正确的把点的等级转化为站的等级。
逻辑为:
在两辆车的最大共同区域里面,(1)有共同的站,(2)但是如果一辆车经过的站多,那么等级低。
问题分解为:
1、找两辆车的最大公共区域(好找,头里面的较大值,尾巴上的较小值)
2、计算公共区域里面的停靠站数
3、车辆数多的等级低
代码:
50分
/*
分析:
低优先度节点指向高优先度节点
*/ #include <iostream>
#include <queue>
#define Maxn 1005
using namespace std;
int n,m;
// stopStation[i][j]表示第i辆车停靠的第j站, stopStation[i][0]表示第i辆车停靠的车站数
int stopStation[Maxn][Maxn];
// adjacentMatrix[i][j]为true表示j车站的优先级比i车站高
// 停了的站的优先级比没停的高
bool adjacentMatrix[Maxn][Maxn];
bool station[Maxn];
int inDegree[Maxn];
//队列里面储存入度为0(也就是当前优先级最低)的节点的编号,
queue<int> que;
bool vis[Maxn]; int priority[Maxn];
int maxPriority; void readData(){
cin>>n>>m;
for(int i=;i<=m;i++){
cin>>stopStation[i][];
for(int j=;j<=stopStation[i][];j++){
cin>>stopStation[i][j];
}
}
} void printRead(){
cout<<"n:"<<n<<" m:"<<m<<endl;
for(int i=;i<=m;i++){
for(int j=;j<=stopStation[i][];j++){
cout<<stopStation[i][j]<<" ";
}
cout<<endl;
}
} void initArr_station(int i){
for(int j=;j<=n;j++){
station[j]=false;
}
for(int j=;j<=stopStation[i][];j++){
int x=stopStation[i][j];
station[x]=true;
}
} void printArr_station(){
for(int j=;j<=n;j++){
cout<<station[j]<<" ";
}
cout<<endl;
} void initArr_adjacentMatrix(){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
adjacentMatrix[Maxn][Maxn]=false;
}
}
//起点站之前的站是没有经过,但是优先级并不比那些停了的站低
//所以我比较优先级只能从起点站开始
//我也只能以终点站结束
for(int i=;i<=m;i++){
initArr_station(i);
int endStation=stopStation[i][stopStation[i][]];
for(int j=stopStation[i][];j<=endStation;j++){
if(station[j]) continue;
for(int k=stopStation[i][];k<=endStation;k++){
if(station[k]){
adjacentMatrix[j][k]=true;
}
}
}
}
} void printArr_adjacentMatrix(){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
cout<<adjacentMatrix[i][j]<<" ";
}
cout<<endl;
}
} void initArr_inDegree(){
for(int i=;i<=n;i++){
inDegree[i]=;
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(adjacentMatrix[i][j]){
inDegree[j]++;
}
}
}
} void printArr_inDegree(){
for(int i=;i<=n;i++){
cout<<inDegree[i]<<" ";
}
cout<<endl;
} void initArr_vis(){
for(int i=;i<=n;i++){
vis[i]=false;
}
} void printArr_vis(){
for(int i=;i<=n;i++){
cout<<vis[i]<<" ";
}
cout<<endl;
} void initArr_priority(){
for(int i=;i<=n;i++){
priority[i]=;
}
} void printArr_priority(){
for(int i=;i<=n;i++){
cout<<priority[i]<<" ";
}
cout<<endl;
} void init(){
readData();
//printRead();
//initArr_station(2);
//printArr_station();
initArr_adjacentMatrix();
//printArr_adjacentMatrix();
initArr_inDegree();
//printArr_inDegree();
initArr_vis();
initArr_priority();
//printArr_priority();
} void removeConnection(int i1){
for(int j=;j<=n;j++){
adjacentMatrix[i1][j]=false;
}
} void topologicalSorting(){
for(int i=;i<=n;i++){
if(inDegree[i]==&&!vis[i]){
vis[i]=true;
que.push(i);
priority[i]=;
}
}
while(!que.empty()){
int i1=que.front();
que.pop();
removeConnection(i1);
initArr_inDegree();
//printArr_inDegree();
for(int i=;i<=n;i++){
if(inDegree[i]==&&!vis[i]){
vis[i]=true;
que.push(i);
priority[i]=priority[i1]+;
}
}
}
} void findHighestPriority(){
maxPriority=;
for(int i=;i<=n;i++){
if(priority[i]>maxPriority){
maxPriority=priority[i];
}
}
} void printAns(){
//printArr_priority();
findHighestPriority();
cout<<maxPriority<<endl;
} int main(){
freopen("4in.txt","r",stdin);
init();
topologicalSorting();
printAns();
return ;
} /*
1、1,n不一定是起点和终点
起点站之前的站是没有经过,但是优先级并不比那些停了的站低
所以我比较优先级只能从起点站开始
2、起点终点不一定是从0开始
*/
80分,比较车的等级
#include <iostream>
#include <queue>
using namespace std;
//记录每辆车停的每个站 stopStation[i][0]表示第i辆车停靠的站
int stopStation[][];
int n,m;
bool adjacentMatrix[][];
//每一辆车的入度
int inDegree[];
bool vis[];
//每一辆车的等级
int priority[];
//最大的等级,因为是从1开始,所以这个值就是答案
int maxPriority;
//队列里面储存入度为0(也就是当前优先级最低)的节点的编号,
//用来做拓扑排序的队列
queue<int> que; //读取数据
void readData(){
cin>>n>>m;
for(int i=;i<=m;i++){
cin>>stopStation[i][];
for(int j=;j<=stopStation[i][];j++){
cin>>stopStation[i][j];
}
}
} //打印读取的数据
void printRead(){
cout<<"n:"<<n<<" m:"<<m<<endl;
for(int i=;i<=m;i++){
for(int j=;j<=stopStation[i][];j++){
cout<<stopStation[i][j]<<" ";
}
cout<<endl;
}
} //增加一辆每个站都停的0号列车
void initArr_stopStation(){
stopStation[][]=n;
for(int j=;j<=stopStation[][];j++){
stopStation[][j]=j;
}
} //打印数据 stopStation
void printArr_stopStation(){
cout<<"n:"<<n<<" m:"<<m<<endl;
for(int i=;i<=m;i++){
for(int j=;j<=stopStation[i][];j++){
cout<<stopStation[i][j]<<" ";
}
cout<<endl;
}
} //找两辆车(第i辆和第j辆)的最大公共区域(好找,头里面的较大值,尾巴上的较小值)
void commonPathArea(int i,int j,int &start,int &end){
int startI=stopStation[i][];
int endI=stopStation[i][stopStation[i][]];
int startJ=stopStation[j][];
int endJ=stopStation[j][stopStation[j][]];
start=max(startI,startJ);
end=min(endI,endJ);
} // 计算第i辆车公共区域[start、end]里面的停靠站数
int stopStationNum(int i,int start,int end){
int num=;
for(int j=;j<=stopStation[i][];j++){
if(stopStation[i][j]>end) break;
if(stopStation[i][j]>=start&&stopStation[i][j]<=end) num++;
}
return num;
} //比较i,j两辆车的等级
int compareGrade(int i,int j){
int start,end;
commonPathArea(i,j,start,end);
int numI=stopStationNum(i,start,end);
int numJ=stopStationNum(j,start,end);
if(numI==numJ) return ;
else if(numI<numJ) return ;//i的等级高
else if(numI>numJ) return -;
} //初始化数据 adjacentMatrix
void initArr_adjacentMatrix(){
for(int i=;i<=m;i++){
for(int j=;j<=m;j++){
adjacentMatrix[i][j]=false;
}
}
} //创建图
void creatGraph(){
for(int i=;i<=m-;i++){
for(int j=i+;j<=m;j++){
if(compareGrade(i,j)==) adjacentMatrix[j][i]=true;
else if(compareGrade(i,j)==-) adjacentMatrix[i][j]=true;
}
}
} //打印图
void printGraph(){
for(int i=;i<=m;i++){
for(int j=;j<=m;j++){
cout<<adjacentMatrix[i][j]<<" ";
}
cout<<endl;
}
} //初始化每辆车的入度
void initArr_inDegree(){
for(int i=;i<=m;i++)
inDegree[i]=;
} //打印每辆车的入度
void printArr_inDegree(){
for(int i=;i<=m;i++)
cout<<inDegree[i]<<" ";
cout<<endl;
} //得到每辆车的入度
void getInDegree(){
for(int i=;i<=m;i++){
for(int j=;j<=m;j++){
if(adjacentMatrix[i][j]) inDegree[j]++;
}
}
} //初始化数据vis
void initArr_vis(){
for(int i=;i<=m;i++)
vis[i]=false;
} //初始化数据 priority
void initArr_priority(){
for(int i=;i<=m;i++)
priority[i]=;
} //打印数组 priority
void printArr_priority(){
for(int i=;i<=m;i++)
cout<<priority[i]<<" ";
cout<<endl;
} //取消节点i到其它节点的连接
void removeConnection(int i){
for(int j=;j<=m;j++){
if(adjacentMatrix[i][j]) inDegree[j]--;
}
} //拓扑排序
void topologicalSorting(){
for(int i=;i<=m;i++){
if(inDegree[i]==&&!vis[i]){
vis[i]=true;
que.push(i);
priority[i]=;
}
}
//printArr_priority();
while(!que.empty()){
int i1=que.front();
que.pop();
removeConnection(i1);
for(int i=;i<=m;i++){
if(inDegree[i]==&&!vis[i]){
vis[i]=true;
que.push(i);
priority[i]=priority[i1]+;
}
}
}
} //找到最高优先级
void findHighestPriority(){
maxPriority=;
for(int i=;i<=m;i++){
if(priority[i]>maxPriority){
maxPriority=priority[i];
}
}
} //打印结果
void printAns(){
//printArr_priority();
findHighestPriority();
cout<<maxPriority<<endl;
} //初始化
void init(){
//读取数据
readData();
//printRead();
//初始化数据 stopStation()
initArr_stopStation();//增加一辆每个站都停的0号列车
//printArr_stopStation();
//initArr_adjacentMatrix();
//创建图
creatGraph();
//printGraph();
//initArr_inDegree();
//得到每辆车的入度
getInDegree();
//printArr_inDegree();
//initArr_vis();
//initArr_priority(); } int main(){
freopen("4in.txt","r",stdin);
//初始化
init();
//拓扑排序
topologicalSorting();
//打印结果
printAns();
return ; }
90分 还是比较站的等级,输入时优化
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e3+,INF=1e9+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,m,s,g[N][N],vis[N],lst[N],ind[N],ans=;
int st[N],top=,buf[N],top2=;
void toposort(){
for(int i=;i<=n;i++) if(ind[i]==) st[++top]=i;
while(top){
ans++;//printf("hi %d %d\n",ans,del);
while(top){
int u=st[top--]; //printf("u %d\n",u);
for(int v=;v<=n;v++) if(g[u][v]){
ind[v]--; //printf("v %d %d\n",v,ind[v]);
if(ind[v]==) buf[++top2]=v;
}
}
for(int i=;i<=top2;i++) st[i]=buf[i];
top=top2;
top2=;
}
} //这是在读数据的时候就完成了各种初始化,减少了循环次数,所以可以多得分
int main(){
freopen("4in.txt","r",stdin);
n=read();m=read();
for(int i=;i<=m;i++){
s=read();
memset(vis,,sizeof(vis));
for(int j=;j<=s;j++) lst[j]=read(),vis[lst[j]]=;
for(int j=lst[];j<=lst[s];j++) if(!vis[j])
for(int k=;k<=s;k++) if(!g[lst[k]][j]) g[lst[k]][j]=,ind[j]++;
}
toposort();
printf("%d",ans);
}