Living-Dream 系列笔记 第37期

Posted on 2024-03-02 16:58  _XOFqwq  阅读(2)  评论(0编辑  收藏  举报

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;
}