【NOIP 2013 普及組】車站分級
阿新 • • 發佈:2018-12-13
【題目】
題目描述:
一條單向的鐵路線上,依次有編號為 1,2,…, 的 個火車站。每個火車站都有一個級別,最低為 1 級。現有若干趟車次在這條線路上行駛,每一趟都滿足如下要求:如果這趟車次停靠了火車站 x,則始發站、終點站之間所有級別大於等於火車站 x 的都必須停靠。(注意:起始站和終點站自然也算作事先已知需要停靠的站點)
例如,下表是 5 趟車次的執行情況。其中,前 4 趟車次均滿足要求,而第 5 趟車次由於停靠了 3 號火車站(2 級)卻未停靠途經的 6 號火車站(亦為 2 級)而不滿足要求。
現有 趟車次的執行情況(全部滿足要求),試推算這 個火車站至少分為幾個不同的級別。
輸入格式:
第一行包含 2 個正整數 , ,用一個空格隔開。 第 行(1 ≤ ≤ )中,首先是一個正整數 (2 ≤ ≤ ),表示第 趟車次有 個停靠站;接下來有 個正整數,表示所有停靠站的編號,從小到大排列。每兩個數之間用一個空格隔開。輸入保證所有的車次都滿足要求。
輸出格式:
輸出只有一行,包含一個正整數,即 個火車站最少劃分的級別數。
樣例資料:
【樣例1】
輸入
9 2
4 1 3 5 6
3 3 5 6
輸出
2
【樣例2】
輸入
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
輸出
3
備註:
【資料範圍】 對於 20% 的資料,1 ≤
【分析】
一開始只是想寫一個暴力騙騙分,結果改了一下就 A 了?
具體做法就是對於一個起點是 ,終點是 的車次,如果 到 中有車站沒停,那麼它們的級別肯定比停過的級別要低,那麼就從沒停的向停過的連一條邊,表示它的級別相對比較低,最後拓撲排序,並且做一個簡單遞推即可
有一個地方要注意,就是要考慮重邊,即如果當前已經有這條邊,以後就不用加了(不然邊數會很多,會炸掉)
好吧我還是看不懂這個O()的演算法是怎麼過的
【程式碼】
#include<stack> #include<cstdio> #include<cstring> #include<algorithm> #define N 1005 #define M 1000005 using namespace std; int n,m,t,ans=1; int a[N],f[N],du[N]; int v[M],next[M],first[N]; bool used[N],have[N][N]; stack<int>sta; void add(int x,int y) { t++; next[t]=first[x]; first[x]=t; v[t]=y; } void link(int x,int s) { int i; for(i=1;i<=s;++i) { if(!have[x][a[i]]) { add(x,a[i]); du[a[i]]++; have[x][a[i]]=true; } } } void topology() { int x,i; for(i=1;i<=n;++i) if(!du[i]) f[i]=1,sta.push(i); while(!sta.empty()) { x=sta.top(); sta.pop(); for(i=first[x];i;i=next[i]) { f[v[i]]=max(f[v[i]],f[x]+1); ans=max(ans,f[v[i]]),--du[v[i]]; if(!du[v[i]]) sta.push(v[i]); } } } int main() { int s,i,j; scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { scanf("%d",&s); memset(used,false,sizeof(used)); for(j=1;j<=s;++j) { scanf("%d",&a[j]); used[a[j]]=true; } for(j=a[1];j<=a[s];++j) if(!used[j]) link(j,s); } topology(); printf("%d",ans); return 0; }