N诺刷题——图论

并查集

1319

#include<iostream>
#include<string>
#include<string.h>
#include<vector>
using namespace std;
int a[1005];
int find(int x)
{
	if(x==a[x])return x;
	a[x]=find(a[x]);
	return a[x];
}
int main()
{
	int m,n;
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)
			break;
		scanf("%d",&m);
		int sum=0;
		for(int i=1;i<=n;i++)
			a[i]=i;
		for(int i=0;i<m;i++)
		{
			int x,y;
			scanf("%d %d",&x,&y);
			int fx=find(x);
			int fy=find(y);
			if(fx!=fy)
			{
				a[fx]=fy;
				sum++;
			}
		}
		printf("%d\n",n-1-sum);
	}
}

1586

#include<iostream>
#include<string>
#include<string.h>
#include<vector>
using namespace std;
const int maxn=10000+5;
int a[maxn];

int find(int x)
{
	if(x==a[x])return x;
	a[x]=find(a[x]);
	return a[x];
}
int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		for(int i=1;i<=n;i++)
			a[i]=i;
		for(int i=0;i<m;i++)
		{
			int z,x,y;
			cin>>z>>x>>y;
			int xi=find(x);
			int yi=find(y);
			if(z==1&&xi!=yi)
				a[xi]=yi;
			else if(z==2)
			{
				if(xi!=yi)
					cout<<"N"<<endl;
				else
					cout<<"Y"<<endl;
			}
		}
	}
	return 0;
}

最小生成树

1312

kruskal算法

一个bug记录
在边记录时

  for(int i=1;i<=n;i++)
        {
            cin>>griph[i].u>>griph[i].v>>griph[i].weight ;
        }
        sort(griph,griph+n,compare);

这样sort排序是没排最后一个

#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<stdio.h>
#include<algorithm>
using namespace std;

struct node
{
	int u;
	int v;
	int weight;
}griph[105];
int a[105];
bool compare(node a,node b)
{
	return a.weight <b.weight ;
}

int find(int x)
{
	if(x==a[x])return x;
	a[x]=find(a[x]);
	return a[x];
}
int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		if(n==0)break;
		int sum=0,flag=0;
		for(int i=1;i<=m;i++)
			a[i]=i;
		//输入
		for(int i=0;i<n;i++)
		{
			cin>>griph[i].u>>griph[i].v>>griph[i].weight ;
		}
		sort(griph,griph+n,compare);

		for(int i=0;i<n;i++)
		{
			int xi=find(griph[i].u);
			int yi=find(griph[i].v);
			if(xi!=yi)
			{
				a[xi]=yi;
				sum+=griph[i].weight ;
				flag++;
			}
		}
		if(flag==m-1)
			cout<<sum<<endl;
		else
			cout<<"?"<<endl;

	}
	return 0;
}
prim算法

讲得很好
https://www.bilibili.com/video/BV1Ua4y1i7tf

Dijkstra算法与Prim算法的区别
https://blog.csdn.net/u012856866/article/details/38726523

1311

直接在上面的那题prim算法的基础上,排序时,先排建好的即可
牛客网出现了内存超限情况,未解决

1341

同上一题,稍微改动

1183

这题只给了点
所以需要先将所有的边的情况求出,然后再按照之前的思路

		for(int i=0;i<n;i++)
			a[i]=i;
		//输入
		for(int i=0;i<n;i++)
		{
			cin>>point[i].x>>point[i].y ;
			for(int j=0;j<i;j++)
			{
				graph[k].u =i;
				graph[k].v=j;
				graph[k].weight =sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)
								+(point[i].y-point[j].y)*(point[i].y-point[j].y));
				k++;
			}
		}
		sort(graph,graph+k,compare);

最短路径问题

相关集合

问题1:为什么Dijkstra算法不能处理带负权边的图
Dijkstra算法在运行过程中维持的关键信息是一组节点集合S,从源节点s到该集合中每个节点之间的最短路径已经被找到。算法重复从节点集合V-S中选择最短路径估计最小的节点u,将u加入到集合S,然后对所有从u出发的边进行松弛操作。
当把一个节点选入集合S时,即意味着已经找到了从源点到这个点的最短路径,但若存在负权边,就与这个前提矛盾,可能会出现得出的距离加上负权后比已经得到S中的最短路径还短。(无法回溯)

问题2:负环
传送门

问题3:松弛
松弛操作是指对于每个顶点v∈V,都设置一个属性d[v],用来描述从源点s到v的最短路径上权值的上界

将图论中的graph比作用毛线和珠子组成的网状结构,两颗珠子之间毛线的长度即edge上的权值,一开始十分松乱的放在桌上。求单源最短路,当发现原点s到欠点u有两条路径,relax操作可以想象成用力把s和u两点往外撑开。这时候像生活中的经验,s和u点之间较短的那条边处于紧绷状态,而较长的那条边处于松弛状态,因此非常形象把这个操作称为松弛操作

SPFA算法 1565

思路:
传送门
代码讲解:
传送门

N诺的那个算法不好理解,直接改下面这个

#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<stdio.h>
#include <queue>
#include<algorithm>
using namespace std;
const int maxn=205;

vector<pair<int,int>>E[maxn];
int n,m;
int d[maxn],inq[maxn];//标记在不在队列

void spfa(int s,int t)
{
	queue<int>q;
	q.push(s),d[s]=0,inq[s]=1;
	while(!q.empty())
	{
		int now=q.front ();
		q.pop();inq[now]=0;
		//遍历顶点所有边
		for(int i=0;i<E[now].size();i++)
		{
			int v=E[now][i].first;
			if(d[v]>d[now]+E[now][i].second )
			{
				d[v]=d[now]+E[now][i].second ;
				if(inq[v]==1)continue;
				inq[v]=1;
				q.push(v);
			}
		}
	}
	cout<<d[t]<<endl;
}

void init()
{
	for(int i=0;i<maxn;i++) E[i].clear();
	for(int i=0;i<maxn;i++) inq[i]=0;
	for (int i=0;i<maxn;i++)d[i]=1e9;
}
int main()
{
	while(cin>>n>>m)
	{
		if(n+m==0)break;
		init();
		for(int i=0;i<m;i++)
		{
			int x,y,z;
			cin>>x>>y>>z;
			//构造邻接表
			E[x].push_back (make_pair(y,z));
			E[y].push_back (make_pair(x,z));
		}
		spfa(1,n);
	}	
	return 0;
}

floyd算法 1565

Dijkstra 算法 1565

通过不,不知为何

http://noobdream.com/DreamJudge/Issue/code/139422/

1344

和1565差不多

1286题一个鸟样

1224

对该算法的理解还需要再加强,
这题在牛客网提交未通过,需要思考迪杰斯特拉算法
上面题目的基础上稍微变形

			flag[now]+=abs(yi[now]-yi[v]);
			if(flag[now]>1)
			{
				flag[now]--;
				continue;
			}

拓扑排序

1566

模板

#include <bits/stdc++.h>
using namespace std;
const int maxn=505;

int len[maxn];
vector<int>a[maxn];

priority_queue <int ,vector<int>,greater<int>>q;
void topo(int n)
{
	for(int i=1;i<=n;i++)
		if(!len[i])q.push(i);
	int flag=0;
	while(!q.empty())
	{
		int now=q.top();
			q.pop();
		if(flag)cout<<" "<<now;
		else cout<<now;
		flag++;
		for(int i=0;i<a[now].size();i++)
		{
			int next=a[now][i];
			len[next]--;
			if(!len[next])q.push(next);
		}
	}
}

int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		memset(len,0,sizeof(len));
		for(int i=0;i<maxn;i++)
			a[i].clear();

		for(int i=0;i<m;i++)
		{
			int x,y;
			cin>>x>>y;
			a[x].push_back (y);//记录顶点的相邻边
			len[y]++;//记录入度
		}
		topo(n);
		cout<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值