1. 程式人生 > >拓撲排序 建圖 模板題 車站分級

拓撲排序 建圖 模板題 車站分級

超水
題目在上面,這個是一個經典的拓撲排序和建圖的模板,大家可以試試水,首先我們要理解題目,假設有一串編號1 3 5,這個就是1,5分別是起點和終點,而且只停靠3,所以2,4這兩個車站必須要小於,1、3、5這三個,而其中三個關係是:1≤3≤5,本著貪心的原則:能等則等所以我們令他們相等,那麼我們可以這樣建圖,如果2<3的話(注意沒有等於),那麼我們就新增一條從2通向3的邊,這樣我們只需要計算生成的這個圖最大有幾層就好了,原因是:如果2->3->5的話意味著2<3<5,所以要三級才可以,這一塊是重點,沒有理解的可以留言。
那麼我們只需要計算圖最大有幾層就好了,我們可以用拓撲排序,然後DP計算,我們定義d[i]表示到i點的最大層數是多少,知道拓撲排序的都知道這個按著拓撲排序DP就好了。
下面上程式碼:

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
queue <int> q;//拓撲排序用的陣列 
int map[1010][1010],num[1010],d[1010],n,v[1010],stan[1010]; 
int read()
{
    char ch;
    while(ch=getchar(),ch<'0' || ch>'9');
    int num=ch-'0';
    while(ch=getchar(),ch>='0'
&& ch<='9') num=num*10+ch-'0'; return num; } void write(int n){ if(n==0) return; write(n/10); putchar(n%10+'0'); } int main() { int m,ans=0,x; n=read(); m=read(); for(int i=1;i<=m;i++)//讀入資料 { int x,s0=0,s1; x=read(); memset(v,0,sizeof
(v)); for(int j=1;j<=x;j++) { stan[j]=read();//快讀一下 v[stan[j]]=1; } for(int j=stan[1]+1;j<stan[x];j++) { if(v[j]==1) continue; for(int k=1;k<=x;k++) { map[j][stan[k]]=1;//尋找沒有停靠的點,在列舉所有有停靠的點見一條從前者到後者的邊 } } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) if(map[i][j]==1) num[j]++;//拓撲排序統計一下每個點的入度 } for(int i=1;i<=n;i++)//入度為0的入隊計算 { if(num[i]!=0) continue; d[i]=1; q.push(i); } while(!q.empty())//迴圈拓撲排序 { x=q.front();//取隊頭 q.pop(); for(int i=1;i<=n;i++)//列舉所有與它相鄰的點 { if(map[x][i]==1)//相鄰 { num[i]--;//去邊 d[i]=max(d[x]+1,d[i]);//DP if(d[i]>ans)//找答案 ans=d[i]; if(num[i]==0) q.push(i); } } } write(ans);//快輸一波 return 0; }

希望大家可以AC,有不懂得可以留言,有錯誤也歡迎指出。