拓扑排序的练习

洛谷P4017 最大食物链计数

题目背景
你知道食物链吗?Delia 生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条。于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧。

题目描述
给你一个食物网,你要求出这个食物网中最大食物链的数量。

(这里的“最大食物链”,指的是生物学意义上的食物链,即最左端是不会捕食其他生物的生产者,最右端是不会被其他生物捕食的消费者。)

Delia 非常急,所以你只有 11 秒的时间。

由于这个结果可能过大,你只需要输出总数模上 8011200280112002 的结果。

输入格式
第一行,两个正整数 n、mn、m,表示生物种类 nn 和吃与被吃的关系数 mm。

接下来 mm 行,每行两个正整数,表示被吃的生物A和吃A的生物B。

输出格式
一行一个整数,为最大食物链数量模上 8011200280112002 的结果。

输入输出样例

输入

5 7
1 2
1 3
2 3
3 5
2 5
4 5
3 4

输出

5

说明/提示
各测试点满足以下约定:
【补充说明】

数据中不会出现环,满足生物学的要求。(感谢 @AKEE )

代码

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int  mod=80112002;
const int M = 5005;
int g[M][M];
int n,m,ans;
int ru[M],chu[M],f[M];
queue<int> q;
int main()
{
	freopen("data.txt","r",stdin);
	cin>>n>>m;
	int a,b;
	for(int i=1;i<=m;i++){
		scanf("%d %d",&a,&b);
		g[a][b]=1;
		chu[a]++;ru[b]++;
	}
	for(int i=1;i<=n;i++){
		if(ru[i]==0){
			f[i]=1;
			q.push(i);
		}
	}
	while(!q.empty()){
		int s=q.front();
		q.pop();
		for(int k=1;k<=n;k++){
			if(g[s][k]==0) continue;
			f[k]+=f[s];
			f[k]%=mod;
			ru[k]--;
			if(ru[k]==0){
				if(chu[k]==0){
					ans+=f[k];
					ans%=mod;
					continue;
				}
				else q.push(k);
			}
			
		}
	}
	cout<<ans<<endl;
	return 0;
}

HDU1285 确定比赛名次

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 55796 Accepted Submission(s): 20508

Problem Description
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

Input
输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

Output
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。

其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

Sample Input

4 3
1 2
2 3
4 3

Sample Output

1 2 4 3

代码

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int N,M;
int g[505][505];
int ru[10005];
int ans[505];
priority_queue<int,vector<int>,greater<int>> q;
int main()
{
	freopen("data.txt","r",stdin);
	while(~scanf("%d %d",&N,&M)){
		int a,b;
		memset(g,0,sizeof(g));
		memset(ru,0,sizeof(ru));
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=M;i++){
			scanf("%d %d",&a,&b);
			if(g[a][b]) continue;
			g[a][b]=1;ru[b]++;
		}
		for(int i=1;i<=N;i++){
			if(ru[i]==0) q.push(i);
		}
		int c=1;
		while(!q.empty()){
			int v=q.top();
			q.pop();
			ans[c++]=v;
			for(int i=1;i<=N;i++){
				if(!g[v][i]) continue;
				ru[i]--;
				if(ru[i]==0) q.push(i);
			}
		}
		for(int i=1;i<=N;i++){
			if(i==1) printf("%d",ans[i]);
			else printf(" %d",ans[i]);
		}
		printf("\n");
		
	}
	
	return 0;
}

POJ1270 Following Orders

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 6520 Accepted: 2685
Description

Order is an important concept in mathematics and in computer science. For example, Zorn’s Lemma states: ``a partially ordered set in which every chain has an upper bound contains a maximal element.’’ Order is also important in reasoning about the fix-point semantics of programs.

This problem involves neither Zorn’s Lemma nor fix-point semantics, but does involve order.
Given a list of variable constraints of the form x < y, you are to write a program that prints all orderings of the variables that are consistent with the constraints.

For example, given the constraints x < y and x < z there are two orderings of the variables x, y, and z that are consistent with these constraints: x y z and x z y.
Input

The input consists of a sequence of constraint specifications. A specification consists of two lines: a list of variables on one line followed by a list of contraints on the next line. A constraint is given by a pair of variables, where x y indicates that x < y.

All variables are single character, lower-case letters. There will be at least two variables, and no more than 20 variables in a specification. There will be at least one constraint, and no more than 50 constraints in a specification. There will be at least one, and no more than 300 orderings consistent with the contraints in a specification.

Input is terminated by end-of-file.
Output

For each constraint specification, all orderings consistent with the constraints should be printed. Orderings are printed in lexicographical (alphabetical) order, one per line.

Output for different constraint specifications is separated by a blank line.
Sample Input

a b f g
a b b f
v w x y z
v y x v z v w v

Sample Output

abfg
abgf
agbf
gabf

wxzvy
wzxvy
xwzvy
xzwvy
zwxvy
zxwvy

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MAX = 200;
char ch1[MAX],ch2[MAX],ch3[MAX];
int n,m;
int zm[MAX],edge[MAX][MAX],to[MAX],vis[MAX],a[MAX];
void DFS(int len)
{
	if(len==n){
		 for(int i=0;i<n;i++)
        {
            printf("%c",ch1[a[i]]);
        }
        printf("\n");
        return ;
	}
	for(int i=0;i<n;i++){
		if(!vis[i]&&!to[i]){
			for(int j=0;j<n;j++){
				if(edge[i][j]==1) to[j]--;
			}//把与这个顶点相连的点入度减1
			vis[i]=1;
			a[len]=i;
			DFS(len+1);
			for(int j=0;j<n;j++)   //还原: 把减掉的入度加回去
            {
                if(edge[i][j]==1)
                {
                    to[j]++;
                }
            }
            vis[i]=0;        //还原: vis变回0 
		}
	}
}
int main()
{
	int pd=0;
	freopen("data.txt","r",stdin);
	while(gets(ch3)){
		n=0;
		if(pd==0)
            pd=1;
        else
            printf("\n");  //测试用例之间输出空行
		gets(ch2);
		//初始化 
		memset(zm,-1,sizeof(zm));
        memset(edge,-1,sizeof(edge));
        memset(to,0,sizeof(to));
        memset(vis,0,sizeof(vis));
        //清除空格
		for(int i=0;ch3[i]!='\0';i++){
			if(ch3[i]==' ') continue;
			ch1[n++]=ch3[i];
		} 
		//排序
		sort(ch1,ch1+n);
		//用zm值来唯一标识ch1中的字母
		for(int i=0;i<n;i++){
			zm[ch1[i]-'a']=i;
		} 
		//设置edge和to (有向边关系和各点入度) 
		for(int i=0;ch2[i]!='\0';i+=4){
			edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1;
			to[zm[ch2[i+2]-'a']]++;
		}
		DFS(0);
	}
	return 0;
} 

牛客 简单拓扑dp

题目描述
(良心出题人wzc说这是个简单拓扑dp,它就必然是一个简单拓扑dp,wzc是不会骗人的)

wzc在一张拓扑图上,他所在的起始位置被标记为0。除了起始位置外,还有被1到n这n个整数所标记的n个顶点,每个顶点i都有一个正整数值xi。
这些顶点之间存在着m条有向边。题目保证图中不存在环,且从顶点0出发必定能到达顶点n。

wzc希望从起点0出发经过某条路径到达顶点n,并且收集经过的所有结点上的数字,使得所有数字的和最大。
现在请你帮wzc求出他能得到的最大数字和是多少。

输入描述:
第一行包含两个整数n,m(1<=n<=1e5,1<=m<=min(n*(n+1)/2,2e5))表示除了起点外的顶点的个数,以及有向边的条数。
第二行为n个空格隔开的整数xi,分别代表顶点1,顶点2,…顶点n上的数字。(1<=xi<=1000)
接下来m行,每行两个整数a,b(0<=a,b<=n),代表有一条有向边从顶点a指向顶点b。
输出描述:
输出一个整数,表示wzc能得到的最大数字和是多少。
示例1
输入

5 6
9 5 8 7 4
0 4
2 1
1 5
3 5
4 3
4 2

输出

25

代码

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
using namespace std;
const int maxn=2e5+10;
vector<int> G[maxn];
ll dp[maxn],val[maxn],cnt[maxn];
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++) scanf("%lld",&val[i]);
	for (int i=1; i<=m; i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		if (v==0) continue;
		G[u].push_back(v);
		cnt[v]+=1;
	}
	queue<int> Q;
	Q.push(0);
	while (!Q.empty()) {
		int u=Q.front();
		Q.pop();
		for (int i=0; i<G[u].size(); i++) {
			int v=G[u][i];
			cnt[v]-=1;
			dp[v]=max(dp[v],dp[u]+val[v]);
			if (cnt[v]==0) Q.push(v);
		}
	}
	printf("%lld\n",dp[n]);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值