并查集
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;
}