5.24总结

题目1:B3644 【模板】拓扑排序 / 家谱树

思路

问题本质:将家族成员组织成一个序列,使得每个成员的后代都排在其后面。这是典型的拓扑排序问题。

建模:将每个家族成员看作图中的节点,若成员A是成员B的后代,则添加一条从B指向A的有向边(B→A)。

拓扑排序:

计算每个节点的入度(指向该节点的边数)。

将所有入度为0的节点加入队列。

依次取出队列中的节点,输出该节点,并将其所有邻接节点的入度减1。若邻接节点入度变为0,则加入队列。

重难点:

正确构建图:输入中第i行描述的是i的后代,因此需要添加边i → x。

处理多解:题目要求任意合法序列,因此使用队列实现时自然满足条件。

代码

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,in[maxn];
vector<int>vt[maxn];
void top_sort(){
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(in[i]==0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int x=q.front();
		cout<<x<<' ';
		q.pop();
		for(int v:vt[x]){
			in[v]--;
			if(in[v]==0){
				q.push(v);
			}
		}
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		while(cin>>x){
			if(x==0){
				break;
			}
			in[x]++;
			vt[i].push_back(x);
		}
	}
	top_sort();
	return 0;
}

题目2:D4282 【例4-13】奖金

思路

问题分析:员工奖金需满足约束(a的奖金 > b的奖金),且总奖金最小。每位员工初始奖金为100元。

建模:若a的奖金应高于b,则添加一条从b指向a的有向边(b→a)。

拓扑排序 + 贪心:

初始化所有员工奖金为100元。

计算每个节点的入度。

将所有入度为0的节点加入队列。

处理队列中的节点:遍历其邻接节点,更新邻接节点的奖金为max(当前奖金, 当前节点奖金 + 1),并减少其入度。若入度变为0,则加入队列。

重难点:

多前驱处理:一个节点的奖金需取所有前驱节点奖金+1的最大值。

环检测:若存在环(无法拓扑排序),则输出"Poor Xed"。

最小化总奖金:通过拓扑序动态更新奖金。

代码

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,in[maxn],ans[maxn];
vector<int>vt[maxn];
int m;
void top_sort(){
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(in[i]==0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int v:vt[x]){
			in[v]--;
			if(in[v]==0){
				q.push(v);
				ans[v]=ans[x]+1;
			}
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		ans[i]=100;
	}
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		vt[y].push_back(x);
		in[x]++;
	}
	top_sort();
	int sum=0;
	for(int i=1;i<=n;i++){
		sum+=ans[i];
	}
	cout<<sum;
	return 0;
}

题目3:P1807 最长路

思路

问题分析:求DAG中从节点1到节点n的最长路径,可能存在负权边。

动态规划 + 拓扑排序:

初始化dist[1] = 0,其他节点为负无穷(-inf)。

预处理:移除从1不可达的入度为0的节点(避免阻塞拓扑排序)。

拓扑排序:从节点1开始,更新每个邻接节点的最长路径dist[v] = max(dist[v], dist[u] + w)。

重难点:

负权边处理:使用负无穷初始化,避免未更新的节点影响结果。

不可达节点处理:通过relax函数移除无关节点。

输出判断:若dist[n]为负无穷,输出-1;否则输出dist[n]。

代码

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,in[maxn],ans[maxn];
struct Node{
	int v,val;
};
vector<Node>vt[maxn];
int m;
void relax(){
	queue<int>q;
	for(int i=2;i<=n;i++){
		ans[i]=-inf;
		if(in[i]==0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(Node v:vt[x]){
			in[v.v]--;
			if(in[v.v]==0){
				q.push(v.v);
			}
		}
	}
}
void top_sort(){
	queue<int>q;
	q.push(1);
	relax();
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(Node v:vt[x]){
			in[v.v]--;
			ans[v.v]=max(ans[v.v],ans[x]+v.val);
			if(in[v.v]==0){
				q.push(v.v);
			}
		}
	}
	if(ans[n]>0){
		cout<<ans[n];
	}
	else{
		cout<<-1;
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		vt[x].push_back({y,z});
		in[y]++;
	}
	top_sort();
	return 0;
}
posted @ 2025-06-04 20:58  KK_SpongeBob  阅读(9)  评论(0)    收藏  举报