T1
令 \(dp_i\) 表示以 \(i\) 结尾的最大食物链条数。
有转移方程:
\[dp_i=\max(dp_i,dp_i+dp_j)(j \in \operatorname{son} i)
\]
按拓扑序转移即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,maxi,ans;
int dp[5031],in[5031],out[5031];
vector<int> G[500031];
const int MOD=80112002;
void topo(){
queue<int> q;
for(int i=1;i<=n;i++) if(!in[i]) q.push(i),dp[i]=1;
while(!q.empty()){
int cur=q.front(); q.pop();
for(int i:G[cur]){
in[i]--,dp[i]=max(dp[i],dp[cur]+dp[i]),dp[i]%=MOD;
if(!in[i]) q.push(i);
}
}
}
signed main(){
cin>>n>>m;
for(int i=1,u,v;i<=m;i++)
cin>>u>>v,G[u].push_back(v),in[v]++,out[u]++;
topo();
for(int i=1;i<=n;i++) if(!out[i]) ans=(ans+dp[i])%MOD;
cout<<ans%MOD;
return 0;
}
T2
令 \(dp_i\) 表示以 \(i\) 结尾的最多游览的城市数量。
有转移方程:
\[dp_i=\max(dp_i,dp_j+1)(j \in \operatorname{son} i)
\]
按拓扑序转移即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,maxi,ans;
int dp[100031],in[100031];
vector<int> G[200031];
const int MOD=80112002;
void topo(){
queue<int> q;
for(int i=1;i<=n;dp[i]=1,i++) if(!in[i]) q.push(i);
while(!q.empty()){
int cur=q.front(); q.pop();
for(int i:G[cur]){
in[i]--,dp[i]=max(dp[i],dp[cur]+1);
if(!in[i]) q.push(i);
}
}
}
signed main(){
cin>>n>>m;
for(int i=1,u,v;i<=m;i++)
cin>>u>>v,G[u].push_back(v),in[v]++;
topo();
for(int i=1;i<=n;i++) cout<<dp[i]<<'\n';
return 0;
}
习题 T1
有点意思的一道题。
若 \(m=n-1\),此时原图呈树,直接 排序 + dfs 求解即可。
若 \(m=n\),此时原图呈基环树,考虑运用 toposort 找环(无向图节点度数为 \(1\) 则入队),
断环成树,依旧仿照上面做即可。正确性显然(可以通过样例理解)。
这样的时间复杂度有点高且实现也有些困难,
因此我们也可以不找环,直接枚举所有边选择断开哪条即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
vector<int> G[10031];
int tot,totp;
int ans[5031],tans[5031];
int vis[5031];
struct E{
int from,to;
}e[10031];
namespace sol1{
void dfs(int x,int f){
if(vis[x]) return;
ans[++tot]=x,vis[x]=1;
for(int i:G[x])
if(i!=f)
dfs(i,x);
}
void solve(){
for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
dfs(1,-1);
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
}
}
namespace sol2{
void dfs(int x,int f,int u,int v){
if(vis[x]) return;
tans[++tot]=x,vis[x]=1;
for(int i:G[x])
if(i!=f&&(!(x==u&&i==v))&&(!(x==v&&i==u)))
dfs(i,x,u,v);
}
bool cmp(int *a,int *b){
for(int i=1;i<=n;i++){
if(a[i]<b[i]) return 1;
if(a[i]>b[i]) return 0;
}
return 0;
}
void solve(){
for(int i=1;i<=n;i++)
sort(G[i].begin(),G[i].end());
bool f=1;
for(int i=1;i<=m;i++){
tot=0,memset(vis,0,sizeof(vis));
dfs(1,-1,e[i].from,e[i].to);
if(f) memcpy(ans,tans,sizeof(ans)),f=0;
if(cmp(tans,ans)&&tot==n)
memcpy(ans,tans,sizeof(ans));
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<' ';
}
}
signed main(){
cin>>n>>m;
for(int i=1,u,v;i<=m;i++)
cin>>u>>v,
G[u].push_back(v),G[v].push_back(u),
e[i].from=u,e[i].to=v;
if(m==n-1)
sol1::solve();
else
sol2::solve();
return 0;
}