洛谷题单【数据结构1-4】图的基本应用

P5318 【深基18.例3】查找文献

思路

bfs和dfs的模板题

实现

#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> a[1000010];
bool visit[1000010];
void dfs(int x,int depth)
{
	visit[x] = 1;
	if(depth==n) 
	{
		cout<<x<<" ";
		return ;
	}
	cout<<x<<" ";
	for(int i=0;i<a[x].size();i++)
	if(!visit[a[x][i]]) dfs(a[x][i],depth+1);
}
void bfs()
{
	queue<int> q;
	q.push(1);
	visit[1] = 0;
	while(!q.empty())
	{
		int s = q.front();
		q.pop();
		cout<<s<<" ";
		for(int i=0;i<a[s].size();i++)
		{
			if(visit[a[s][i]]) 
			{
				q.push(a[s][i]);
				visit[a[s][i]] = 0;
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	int t1,t2;
	for(int i=1;i<=m;i++)
	{
		cin>>t1>>t2;
		a[t1].push_back(t2);
	}
	for(int i=1;i<=n;i++)
	sort(a[i].begin(),a[i].end());
	
	dfs(1,1);
	cout<<endl;
	bfs();
}

P3916 图的遍历

思路

反向建立边,从节点最大的开始dfs,把沿途所有点的值都修改

实现

#include<bits/stdc++.h>
using namespace std;
#define MAXL 100010

int N, M, A[MAXL];
vector<int> G[MAXL]; 

void dfs(int x, int d) {
	if(A[x]) return; 
	A[x] = d;
	for(int i=0; i<G[x].size(); i++)
		dfs(G[x][i], d);
}

int main() {
	int u, v;
	scanf("%d%d", &N, &M);
	for(int i=1; i<=M; i++) {
		scanf("%d%d", &u, &v);
		G[v].push_back(u); 
	}
	for(int i=N; i; i--) dfs(i, i); 
	for(int i=1; i<=N; i++) printf("%d ", A[i]);
	printf("\n");
	return 0;
}

P1113 杂务

思路

拓扑排序
本题数据特殊,是有序的。因此可以在输入时处理,建图意义不大

实现

//来自Nishikino_Curtis
#include<bits/stdc++.h>
using namespace std;
int n,l,t,ans[10005],maxans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&i);
        scanf("%d",&l);
        int tmp=0;
        while(scanf("%d",&t)&&t)
            tmp=max(ans[t],tmp);
        ans[i]=tmp+l;
        maxans=max(ans[i],maxans);
    } 
    printf("%d\n",maxans);
    return 0;
 }

P4017 最大食物链计数

思路

边拓扑排序边维护从生产者到该节点有多少条路(路的条数等于所有指向它的节点的路的条数之和)

实现

一个有错误的实现 有空改改

#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
int h[N], e[N], ne[N], idx;
int q[N], d[N];
int ans[N];
int n,m;
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int topsort()
{
    int hh = 0, tt = -1;

    // d[i] 存储点i的入度
    for (int i = 1; i <= n; i ++ )
        if (!d[i])
            q[ ++ tt] = i;

    while (hh <= tt)
    {
    	
        int t = q[hh ++ ];
//        cout<<endl;
//        cout<<t<<"   ";
        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
//            cout<<j;
            ans[j] += ans[t];
            ans[j]%=80112002;
            if (-- d[j] == 0)
                q[ ++ tt] = j;
                
        }
    }
    // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
    return q[tt];
}
int main()
{
	idx = 0;
	memset(h, -1, sizeof h);
	cin>>n>>m;
	vector<bool> eat(n+1,0);
	int t1,t2;
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&t1,&t2);
		d[t2]++;
		add(t1,t2);
		eat[t1] = 1;
	}
	int res = 0;
	ans[1] = 1; 
	topsort();
	for(int i=1;i<=n;i++)
	{
		if(!eat[i])
		res = (ans[i]+res)%80112002;
	}
	cout<<res;
    return 0;
 }

P1807 最长路

思路

给边权求相反数,转换为求最短路问题

实现

#include<bits/stdc++.h>
using namespace std;
int main(){
    int dis[50001],w[50001],n,m,minn,f[50001][3];
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        dis[i]=w[i]=100000000;
        f[i][1]=f[i][2]=0;
    }
    for(int i=1;i<=m;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        f[i][1]=a,f[i][2]=b,w[i]=-c;
    }
    dis[1]=0;
    for(int i=1;i<=n-1;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)
    printf("%d",-dis[n]);
    else printf("-1");
    return 0;
}

P2853 [USACO06DEC]Cow Picnic S

思路

从k个奶牛出发,dfs且记录每一个牧场被遍历的次数。被遍历次数等于k的牧场符合条件。

实现

#include<bits/stdc++.h>
using namespace std;
bool vis[1010];
int k,n,m,ans;
int mk[1010],a[1010];
vector <int> b[1010];
void dfs(int x)
{
     vis[x]=1;  mk[x]++;
     for(int i=0;i<b[x].size();i++)
         if(!vis[b[x][i]])
             dfs(b[x][i]);
}
int main()
{
    int x,y;
    cin>>k>>n>>m;
    for(int i=1;i<=k;i++) cin>>a[i];
    for(int i=1;i<=m;i++) 
    {
        cin>>x>>y;
        b[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(mk[i]==k) ans++;
    cout<<ans;
    return 0;
}

P1347 排序

思路

自己写出来不对 绿题果然还是难的 = =
来自题解区 mydiplomacy

  • 条件有矛盾:没有点入度为0,或者最后在队列里的节点数<n
  • 条件不足:有不止一个点入度为零,或当取同一个队首u时有不止一个v的入度变成了零
  • 排序成功:非上两种情况

实现

来自题解区 mydiplomacy

#include<bits/stdc++.h>
using namespace std;
const int maxn=30,maxm=905;

struct Node
{
	int v;
	Node *next;
}*h[maxn],pool[maxm];
int tot;
int du[maxn];
int q[maxn],head,tail;
int n,m;

void addEdge(int u, int v)
{
	Node *p=&pool[++tot];
	p->v=v; p->next=h[u]; h[u]=p;
}

int toposort() //返回值为1代表成立,返回值为0代表条件不足,返回值为-1代表条件矛盾
{
	int temp=0;
	int f=0;
	for(int i=1;i<=n;i++)
	{
		if(du[i]==0)
		{
			q[tail++]=i;
			temp++;
	    } 
    }
    if(temp>1)
    	f=1;
    while(head<tail)
    {
    	temp=0;
    	int u=q[head++];
    	for(Node *p=h[u];p;p=p->next)
    	{
    		du[p->v]--;
    		if(du[p->v]==0)
    		{
    			q[tail++]=p->v;
    			temp++;
    		}
		}
		if(temp>1)
			f=1;
    }
    if(tail!=n)
    	return -1;
    else
		if(f==1)
			return 0;
	else return 1;
}	

struct Edge
{
	int u,v;
}a[maxm];

int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		char aa,bb,cc;
		cin>>aa>>bb>>cc;
		a[i].u=aa-'A'+1; a[i].v=cc-'A'+1;
    }
    for(int i=1;i<=m;i++)
    {
    	addEdge(a[i].u,a[i].v);
    	head = tail = 0;
    	memset(du,0,sizeof(du));
    	for(int j=1;j<=i;j++) du[a[j].v]++;
    	int flag=toposort();
    	if(flag==1)
    	{
    		cout<<"Sorted sequence determined after "<<i<<" relations: ";
			for(int j=0;j<=n-1;j++)
			{
				cout<<(char)(q[j]+'A'-1);
		    }
		    cout<<'.'<<endl;
		    return 0;
        }
        else if(flag==0) continue;
        else
        {
        	cout<<"Inconsistency found after ";
        	cout<<i<<" relations."<<endl;
        	return 0;
        }
    }
    cout<<"Sorted sequence cannot be determined."<<endl;
	return 0;
}

P1983 [NOIP2013 普及组] 车站分级

思路

建图时添加从停靠站到未停靠站的边,拓扑排序记录一共有几层

实现

来自 黄毛猫_HYX

#include<bits/stdc++.h>
#define N 1005
using namespace std;
int n,m,ans,st[N],s,tuopu[N][N],de[N],tt[N],top;
bool is[N],bo[N];			
int main() {
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++) {
        memset(is,0,sizeof(is));//is表示是否是停靠站
        scanf("%d",&s);
        for(int j=1;j<=s;j++)
            scanf("%d",&st[j]),is[st[j]]=true;
        for(int j=st[1];j<=st[s];j++)
            if(!is[j])			//枚举站点,若不是已停靠的就小于所有停靠站的等级
                for(int k=1;k<=s;k++)	//枚举已停靠站点
                    if(!tuopu[j][st[k]]) tuopu[j][st[k]]=1,de[st[k]]++;//tuopu[i][j]表示j>i的级别,如上
    }
    
    do{
        top=0;
        for(int i=1;i<=n;i++)
            if(de[i]==0&&!bo[i]) {
                tt[++top]=i,bo[i]=true;//开始将出度为0的点删掉
            }
        for(int i=1;i<=top;i++)
            for(int j=1;j<=n;j++)
                if(tuopu[tt[i]][j]) tuopu[tt[i]][j]=0,de[j]--;//去边去点
        ans++;
    } while(top);
    printf("%d",ans-1);//最后一次什么点都没有会多算一次(自行理解)
    return 0;
}

欢迎指正

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值