[NOIP2013 普及組] 車站分級
阿新 • • 發佈:2021-11-19
分析
這題還是比較好分析的
利用了,逆向思維。
當我們知道一個車次中所有能停靠的站後,通過題目可知,對停靠的每個點而言,沒有停靠的一定不大於停靠點。
因此就好辦了,我們知道每個車次之後,將所有的非停靠點和停靠點之間連一個邊。
因為題目保證一定有解,則一定是無環的,因此直接跑一遍拓撲序即可。
兩種存圖方式
鄰接矩陣
我們可以注意到,該題的邊數最多有,5005001000,如果用連結串列直接儲存的話,直接就會爆炸。
所有我的想法是,就存一個鄰接矩陣嘛,問題也不大
Ac_code
#include<bits/stdc++.h> using namespace std; const int N = 1010; int stop[N],d[N],f[N]; bool st[N],g[N][N]; int n,m; template < typename T > inline void read(T &x) { x = 0; bool f = 0; char ch = getchar(); while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();} while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar(); x = f ? -x : x; } void topsort() { queue<int> q; for(int i=1;i<=n;i++) if(!d[i]) { q.push(i); f[i]=1; //cout<<i<<endl; } while(q.size()) { auto t = q.front(); q.pop(); for(int i=1;i<=n;i++) if(g[t][i]) { if(--d[i]==0) q.push(i); f[i]=max(f[i],f[t]+1); } } } int main() { read(n),read(m); while(m--) { for(int i=1;i<=n;i++) st[i]=0; int t,mmin=n,mmax = 1,cnt=0; read(t); while(t--) { int x; read(x); stop[cnt++]=x; st[x]=1; mmin=min(mmin,x); mmax=max(mmax,x); } for(int i=0;i<cnt;i++) for(int j=mmin;j<=mmax;j++) if(!st[j]&&!g[j][stop[i]]){//這裡卡了我半天,emmm,如果有重邊,那要排除掉 g[j][stop[i]]=1,d[stop[i]]++; } } topsort(); int ans = 0; for(int i=1;i<=n;i++) ans=max(ans,f[i]); cout<<ans<<endl; }
鄰接表
這裡如果直接用鄰接表的話會直接炸掉。
所以我們,用了一個小技巧。
如果想在兩個集合終點任意兩點之間連一條邊,那可以在兩個集合中間,建一個虛擬點,將左邊所有點,連線一個邊權為0的邊到虛擬點上,再從虛擬點連線邊權為1的邊到右邊的集合中所有點。
這樣邊數,就從nm變為了n+m
#include<bits/stdc++.h> using namespace std; const int N = 2e3 + 10,M = 2e6 + 10; int h[N],e[M],ne[M],w[M],idx; int q[N],d[N]; bool st[N]; int dist[N]; int n,m; void add(int a,int b,int c) { e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++,d[b]++; } void topsort() { int hh=0,tt=-1; for(int i=1;i<=n+m;i++) if(!d[i]) q[++tt]=i; while(hh<=tt) { int t = q[hh++]; for(int i = h[t];~i;i=ne[i]) { int j = e[i]; if(--d[j]==0) q[++tt]=j; } } } int main() { scanf("%d%d",&n,&m); memset(h,-1,sizeof h); for(int i=1;i<=m;i++) { memset(st, 0, sizeof st); int s; scanf("%d",&s); int start=n,end=1; while(s--) { int t; scanf("%d",&t); start=min(start,t); end=max(end,t); st[t]=1; } int ver = i + n; for(int j=start;j<=end;j++) if(st[j]) add(ver,j,1); else add(j,ver,0); } topsort(); for(int i=1;i<=n;i++) dist[i]=1; for(int i=0;i<n+m;i++) { int j = q[i]; for(int k = h[j];~k;k=ne[k]) dist[e[k]]=max(dist[e[k]],dist[j]+w[k]); } int res = 0; for(int i=1;i<=n;i++) res=max(res,dist[i]); printf("%d\n",res); return 0; }