java 车站分级问题_【NOIP2013 普及组】车站分级

【NOIP2013 普及组】车站分级

一、题目

【NOIP2013 普及组】车站分级

时间限制: 1 Sec  内存限制: 128 MB

提交: 3  解决: 0

[提交][状态][讨论版]

题目描述

0e9dd8069282f3d0dc0187bcf818db59.png

一条单向的铁路线上,依次有编号为 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%的数据,我们知道对于每一列车,它经过的站点中停了的站点的等级肯定比没停的站点高。因此对于每一辆车,我们可以把它经过的每一个没停的站点向每一个停了的站点建一条边。然后我们会得到一张图,在这张图上找最长的一条路段即可。

然后考虑正解,显然对于点考虑是无法再优化了,因此我们考虑车。我们定义一辆车的等级就是它经过站点的最小等级。我们考虑如何判定两辆车的等级大小。

对于两辆车,它们如果没有交点,那么它们的等级没有关系。

两辆车相交区间(都有停的区间)中,如果一辆车停的车辆多,那么它的等级低。

8ac51790cf4fb86f18d1bea06cc06cd8.png

于是我们就建立了两辆车之间的大小关系,同样的,应用拓扑排序就可以找到这个最大的等级。

最后,还有一点要注意,因为我们处理的是车,而最后要求的是点。如果对于一辆等级为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分

1 /*

2 分析:3 低优先度节点指向高优先度节点4 */

5

6 #include

7 #include

8 #define Maxn 1005

9 using namespacestd;10 intn,m;11 //stopStation[i][j]表示第i辆车停靠的第j站, stopStation[i][0]表示第i辆车停靠的车站数

12 intstopStation[Maxn][Maxn];13 //adjacentMatrix[i][j]为true表示j车站的优先级比i车站高14 //停了的站的优先级比没停的高

15 booladjacentMatrix[Maxn][Maxn];16 boolstation[Maxn];17 intinDegree[Maxn];18 //队列里面储存入度为0(也就是当前优先级最低)的节点的编号,

19 queueque;20 boolvis[Maxn];21

22 intpriority[Maxn];23 intmaxPriority;24

25 voidreadData(){26 cin>>n>>m;27 for(int i=1;i<=m;i++){28 cin>>stopStation[i][0];29 for(int j=1;j<=stopStation[i][0];j++){30 cin>>stopStation[i][j];31 }32 }33 }34

35 voidprintRead(){36 cout<

45 void initArr_station(inti){46 for(int j=1;j<=n;j++){47 station[j]=false;48 }49 for(int j=1;j<=stopStation[i][0];j++){50 int x=stopStation[i][j];51 station[x]=true;52 }53 }54

55 voidprintArr_station(){56 for(int j=1;j<=n;j++){57 cout<

62 voidinitArr_adjacentMatrix(){63 for(int i=1;i<=n;i++){64 for(int j=1;j<=n;j++){65 adjacentMatrix[Maxn][Maxn]=false;66 }67 }68 //起点站之前的站是没有经过,但是优先级并不比那些停了的站低69 //所以我比较优先级只能从起点站开始70 //我也只能以终点站结束

71 for(int i=1;i<=m;i++){72 initArr_station(i);73 int endStation=stopStation[i][stopStation[i][0]];74 for(int j=stopStation[i][1];j<=endStation;j++){75 if(station[j]) continue;76 for(int k=stopStation[i][1];k<=endStation;k++){77 if(station[k]){78 adjacentMatrix[j][k]=true;79 }80 }81 }82 }83 }84

85 voidprintArr_adjacentMatrix(){86 for(int i=1;i<=n;i++){87 for(int j=1;j<=n;j++){88 cout<

94 voidinitArr_inDegree(){95 for(int i=1;i<=n;i++){96 inDegree[i]=0;97 }98 for(int i=1;i<=n;i++){99 for(int j=1;j<=n;j++){100 if(adjacentMatrix[i][j]){101 inDegree[j]++;102 }103 }104 }105 }106

107 voidprintArr_inDegree(){108 for(int i=1;i<=n;i++){109 cout<

114 voidinitArr_vis(){115 for(int i=1;i<=n;i++){116 vis[i]=false;117 }118 }119

120 voidprintArr_vis(){121 for(int i=1;i<=n;i++){122 cout<

127 voidinitArr_priority(){128 for(int i=1;i<=n;i++){129 priority[i]=0;130 }131 }132

133 voidprintArr_priority(){134 for(int i=1;i<=n;i++){135 cout<

140

141 voidinit(){142 readData();143 //printRead();144 //initArr_station(2);145 //printArr_station();

146 initArr_adjacentMatrix();147 //printArr_adjacentMatrix();

148 initArr_inDegree();149 //printArr_inDegree();

150 initArr_vis();151 initArr_priority();152 //printArr_priority();

153 }154

155 void removeConnection(inti1){156 for(int j=1;j<=n;j++){157 adjacentMatrix[i1][j]=false;158 }159 }160

161 voidtopologicalSorting(){162 for(int i=1;i<=n;i++){163 if(inDegree[i]==0&&!vis[i]){164 vis[i]=true;165 que.push(i);166 priority[i]=1;167 }168 }169 while(!que.empty()){170 int i1=que.front();171 que.pop();172 removeConnection(i1);173 initArr_inDegree();174 //printArr_inDegree();

175 for(int i=1;i<=n;i++){176 if(inDegree[i]==0&&!vis[i]){177 vis[i]=true;178 que.push(i);179 priority[i]=priority[i1]+1;180 }181 }182 }183 }184

185 voidfindHighestPriority(){186 maxPriority=0;187 for(int i=1;i<=n;i++){188 if(priority[i]>maxPriority){189 maxPriority=priority[i];190 }191 }192 }193

194 voidprintAns(){195 //printArr_priority();

196 findHighestPriority();197 cout<

200 intmain(){201 freopen("4in.txt","r",stdin);202 init();203 topologicalSorting();204 printAns();205 return 0;206 }207

208 /*

209 1、1,n不一定是起点和终点210 起点站之前的站是没有经过,但是优先级并不比那些停了的站低211 所以我比较优先级只能从起点站开始212 2、起点终点不一定是从0开始213 */

80分,比较车的等级

1 #include

2 #include

3 using namespacestd;4 //记录每辆车停的每个站 stopStation[i][0]表示第i辆车停靠的站

5 int stopStation[1005][1005];6 intn,m;7 bool adjacentMatrix[1005][1005];8 //每一辆车的入度

9 int inDegree[1005];10 bool vis[1005];11 //每一辆车的等级

12 int priority[1005];13 //最大的等级,因为是从1开始,所以这个值就是答案

14 intmaxPriority;15 //队列里面储存入度为0(也就是当前优先级最低)的节点的编号,16 //用来做拓扑排序的队列

17 queueque;18

19 //读取数据

20 voidreadData(){21 cin>>n>>m;22 for(int i=1;i<=m;i++){23 cin>>stopStation[i][0];24 for(int j=1;j<=stopStation[i][0];j++){25 cin>>stopStation[i][j];26 }27 }28 }29

30 //打印读取的数据

31 voidprintRead(){32 cout<

41 //增加一辆每个站都停的0号列车

42 voidinitArr_stopStation(){43 stopStation[0][0]=n;44 for(int j=1;j<=stopStation[0][0];j++){45 stopStation[0][j]=j;46 }47 }48

49 //打印数据 stopStation

50 voidprintArr_stopStation(){51 cout<

60 //找两辆车(第i辆和第j辆)的最大公共区域(好找,头里面的较大值,尾巴上的较小值)

61 void commonPathArea(int i,int j,int &start,int &end){62 int startI=stopStation[i][1];63 int endI=stopStation[i][stopStation[i][0]];64 int startJ=stopStation[j][1];65 int endJ=stopStation[j][stopStation[j][0]];66 start=max(startI,startJ);67 end=min(endI,endJ);68 }69

70 //计算第i辆车公共区域[start、end]里面的停靠站数

71 int stopStationNum(int i,int start,intend){72 int num=0;73 for(int j=1;j<=stopStation[i][0];j++){74 if(stopStation[i][j]>end) break;75 if(stopStation[i][j]>=start&&stopStation[i][j]<=end) num++;76 }77 returnnum;78 }79

80 //比较i,j两辆车的等级

81 int compareGrade(int i,intj){82 intstart,end;83 commonPathArea(i,j,start,end);84 int numI=stopStationNum(i,start,end);85 int numJ=stopStationNum(j,start,end);86 if(numI==numJ) return 0;87 else if(numI

88 else if(numI>numJ) return -1;89 }90

91 //初始化数据 adjacentMatrix

92 voidinitArr_adjacentMatrix(){93 for(int i=0;i<=m;i++){94 for(int j=0;j<=m;j++){95 adjacentMatrix[i][j]=false;96 }97 }98 }99

100 //创建图

101 voidcreatGraph(){102 for(int i=0;i<=m-1;i++){103 for(int j=i+1;j<=m;j++){104 if(compareGrade(i,j)==1) adjacentMatrix[j][i]=true;105 else if(compareGrade(i,j)==-1) adjacentMatrix[i][j]=true;106 }107 }108 }109

110 //打印图

111 voidprintGraph(){112 for(int i=0;i<=m;i++){113 for(int j=0;j<=m;j++){114 cout<

120 //初始化每辆车的入度

121 voidinitArr_inDegree(){122 for(int i=0;i<=m;i++)123 inDegree[i]=0;124 }125

126 //打印每辆车的入度

127 voidprintArr_inDegree(){128 for(int i=0;i<=m;i++)129 cout<

133 //得到每辆车的入度

134 voidgetInDegree(){135 for(int i=0;i<=m;i++){136 for(int j=0;j<=m;j++){137 if(adjacentMatrix[i][j]) inDegree[j]++;138 }139 }140 }141

142 //初始化数据vis

143 voidinitArr_vis(){144 for(int i=0;i<=m;i++)145 vis[i]=false;146 }147

148 //初始化数据 priority

149 voidinitArr_priority(){150 for(int i=0;i<=m;i++)151 priority[i]=0;152 }153

154 //打印数组 priority

155 voidprintArr_priority(){156 for(int i=0;i<=m;i++)157 cout<

161 //取消节点i到其它节点的连接

162 void removeConnection(inti){163 for(int j=0;j<=m;j++){164 if(adjacentMatrix[i][j]) inDegree[j]--;165 }166 }167

168 //拓扑排序

169 voidtopologicalSorting(){170 for(int i=0;i<=m;i++){171 if(inDegree[i]==0&&!vis[i]){172 vis[i]=true;173 que.push(i);174 priority[i]=1;175 }176 }177 //printArr_priority();

178 while(!que.empty()){179 int i1=que.front();180 que.pop();181 removeConnection(i1);182 for(int i=0;i<=m;i++){183 if(inDegree[i]==0&&!vis[i]){184 vis[i]=true;185 que.push(i);186 priority[i]=priority[i1]+1;187 }188 }189 }190 }191

192 //找到最高优先级

193 voidfindHighestPriority(){194 maxPriority=0;195 for(int i=0;i<=m;i++){196 if(priority[i]>maxPriority){197 maxPriority=priority[i];198 }199 }200 }201

202

203 //打印结果

204 voidprintAns(){205 //printArr_priority();

206 findHighestPriority();207 cout<

210 //初始化

211 voidinit(){212 //读取数据

213 readData();214 //printRead();215 //初始化数据 stopStation()

216 initArr_stopStation();//增加一辆每个站都停的0号列车217 //printArr_stopStation();218 //initArr_adjacentMatrix();219 //创建图

220 creatGraph();221 //printGraph();222 //initArr_inDegree();223 //得到每辆车的入度

224 getInDegree();225 //printArr_inDegree();226 //initArr_vis();227 //initArr_priority();

228

229 }230

231

232 intmain(){233 freopen("4in.txt","r",stdin);234 //初始化

235 init();236 //拓扑排序

237 topologicalSorting();238 //打印结果

239 printAns();240 return 0;241

242 }

90分 还是比较站的等级,输入时优化

1 #include

2 #include

3 #include

4 #include

5 using namespacestd;6 const int N=1e3+5,INF=1e9+5;7 inline intread(){8 char c=getchar();int x=0,f=1;9 while(c'9'){if(c=='-')f=-1;c=getchar();}10 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}11 return x*f;12 }13 int n,m,s,g[N][N],vis[N],lst[N],ind[N],ans=0;14 int st[N],top=0,buf[N],top2=0;15 voidtoposort(){16 for(int i=1;i<=n;i++) if(ind[i]==0) st[++top]=i;17 while(top){18 ans++;//printf("hi %d %d\n",ans,del);

19 while(top){20 int u=st[top--]; //printf("u %d\n",u);

21 for(int v=1;v<=n;v++) if(g[u][v]){22 ind[v]--; //printf("v %d %d\n",v,ind[v]);

23 if(ind[v]==0) buf[++top2]=v;24 }25 }26 for(int i=1;i<=top2;i++) st[i]=buf[i];27 top=top2;28 top2=0;29 }30 }31

32 //这是在读数据的时候就完成了各种初始化,减少了循环次数,所以可以多得分

33 intmain(){34 freopen("4in.txt","r",stdin);35 n=read();m=read();36 for(int i=1;i<=m;i++){37 s=read();38 memset(vis,0,sizeof(vis));39 for(int j=1;j<=s;j++) lst[j]=read(),vis[lst[j]]=1;40 for(int j=lst[1];j<=lst[s];j++) if(!vis[j])41 for(int k=1;k<=s;k++) if(!g[lst[k]][j]) g[lst[k]][j]=1,ind[j]++;42 }43 toposort();44 printf("%d",ans);45 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值