11/23 洛谷

P3916 图的遍历

反向建边 + dfs

按题目来每次考虑每个点可以到达点编号最大的点,不如考虑较大的点可以反向到达哪些点

循环从N到1,则每个点i能访问到的结点的A值都是i

每个点访问一次,这个A值就是最优的,因为之后如果再访问到这个结点那么答案肯定没当前大了

#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
 const int N=100010;
using namespace std;
 vector<int>G[N];//vector存图 
 int n,m;
 int A[N];
 void dfs(int x,int d){
   if(A[x]!=0)return ;//访问过 
   A[x]=d;
   for(int i=0;i<G[x].size();i++){
      dfs(G[x][i],d);
   }
 }
 int main(){
   int x,y;
   cin>>n>>m;
   while(m--){
      cin>>x>>y;
      G[y].push_back(x);//反向建边 
   }
   for(int i=n;i;i--){
      dfs(i,i);
   }
   for(int i=1;i<=n;i++){
      cout<<A[i]<<" ";
   }
   
     return 0;
  }

P1807 最长路

#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
 
using namespace std;
 int dis[50001],w[50001];
 int n,m,minn,f[50001][3];
 int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
      dis[i]=w[i]=100000;
      f[i][1]=f[i][2]=0;
    }
    for(int i=1;i<=m;i++){
      int a,b,c;
      cin>>a>>b>>c;
      f[i][1]=a,f[i][2]=b,w[i]=-c;
    }
    dis[1]=0;
    for(int i=1;i<=n;i++){
      for(int j=1;j<=m;j++){
         dis[f[j][2]]=min(dis[f[j][2]],dis[f[j][1]]+w[j]);
      }
    }   
    if(dis[n]!=0){
      cout<<-dis[n];
    }else{
      cout<<"-1";
    }

     return 0;
  }

P2853 [USACO06DEC]Cow Picnic S

从k个奶牛分别dfs,用mk[i]表示第i个牧场被遍历过多少次,最后只有mk[i]==k的牧场满足条件。无权的有向图也可以用vector存储。

#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
 
using namespace std;
 int k,N,M;
 //int G[10001][10010];
 vector<int>G[10001];
 bool vis[10001];
 int a[10001],ans[10001];
 int cnt;
 void dfs(int x){
    if(!vis[x])ans[x]++;
    else vis[x]=1;
    for(int i=0;i<G[x].size();i++){
      dfs(G[x][i]);
    }
 }
 int main(){
   cin>>k>>N>>M;
   for(int i=1;i<=k;i++)cin>>a[i];
   for(int i=1;i<=M;i++){
      int x,y;
      cin>>x>>y;
      G[x].push_back(y);
   }
   for(int i=1;i<=k;i++){
      for(int j=1;j<=N;j++){
         vis[j]=0;
      }
      dfs(a[i]);
   }
   for(int i=1;i<=N;i++){
      if(ans[i]==k)cnt++;
   }
   cout<<cnt;
 
     return 0;
  }

P4017 最大食物链计数

1、这是一道图论题;

2、不是求最短路;

3、根据提示“最左端是不会捕食其他生物的生产者”可以想到,我们要入度为零的点开始查找;

4、再看一遍题目,就是求路径数,当且仅当一个点的入度变为零时才需要入队,并不是数据更新一次就要入队;

5、出度为零的点的路径总数和就是答案。

思路已经呼之欲出了:拓扑排序!```

```cpp
在这里插入代码片

拓扑排序模板:

#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
 #include<queue>
using namespace std;
queue<int>q;
int mp[5005][5005];
 int n,m,ru[5005],chu[5005],a,b,f[5005],ans;
 int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
      cin>>a>>b;
      mp[a][b]=1;
      chu[a]++;
      ru[b]++;
    }
    //步骤1
    for(int i=1;i<=n;i++){
      if(ru[i]==0){
         f[i]=1;
         q.push(i);
      }
    }
    while(!q.empty())
    {
      int a=q.front();
      q.pop();
      //步骤二
      for(int k=1;k<=n;k++)
      {
         /*
         一些操作
         */
         if(ru[k]==0){//步骤三
           /*if(chu[k]==0){
               ans+=f[k];
               ans%=80112002;
               continue;
               }*/ 
               
		//其他操作         }
            q.push(k);
         }
      }
    }
    cout<<ans;
     return 0;
  }

对于这道题:

#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
#include<iomanip>
#include<vector>
 #include<queue>
using namespace std;
queue<int>q;
int mp[5005][5005];
 int n,m,ru[5005],chu[5005],a,b,f[5005],ans;
 int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
      scanf("%d%d", &a, &b);
      mp[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 a=q.front();
      q.pop();
      for(int k=1;k<=n;k++)
      {
         if(mp[a][k]==0)continue;
         f[k]+=f[a];
         f[k]%=80112002;
         ru[k]--;
         if(ru[k]==0){
            if(chu[k]==0){
               ans+=f[k];
               ans%=80112002;
               continue;
            }
            q.push(k);
         }
      }
    }
    cout<<ans;
     return 0;
  }

P1113 杂务

拓扑排序
总结一下,此种拓扑排序共有四个主要步骤:
  • 初始化队列,将入度为 00 的节点放入队列。
  • 取出队首,遍历其出边,将能够到达的点入度减一,同时维护答案数组。
  • 若在此时一个点的入度变为 11,那么将其加入队列。
  • 回到第二步,直到队列为空。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>

#define ll long long

using namespace std;

inline int read() {
	int x=0,f=1;
	char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x*f;
}

const int N=500005;

int ind[N],f[N],a[N];  //ind--入度   f--答案   a--时间
vector <int> edge[N];
queue <int> q;

int main() {
	int n=read();
	for (int i=1;i<=n;i++) {
		int x=read();
		a[i]=read();
		while (int y=read()) {
			if (!y) break;
			edge[y].push_back(x);
            ind[x]++;
		}
	}
    //步骤一
	for (int i=1;i<=n;i++) {
		if (ind[i]==0) {
			q.push(i);
			f[i]=a[i];
		}
	};
	while (!q.empty()) {
		int rhs=q.front();
		q.pop();
        //步骤二
		for (int i=0;i<edge[rhs].size();i++) {
			int u=edge[rhs][i];
			ind[u]--;
			if (ind[u]==0) q.push(u);  //步骤三
			f[u]=max(f[u],f[rhs]+a[u]);
		}
	}
	int ans=0;
	for (int i=1;i<=n;i++) {
		ans=max(ans,f[i]);   //统计答案
	}
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值