拓撲排序 建圖 模板題 車站分級
阿新 • • 發佈:2019-01-30
超水
題目在上面,這個是一個經典的拓撲排序和建圖的模板,大家可以試試水,首先我們要理解題目,假設有一串編號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,有不懂得可以留言,有錯誤也歡迎指出。