#include
using namespace std;
#define inf 0x7fffffff
int n,m,sum;
int dis[5005],vis[5005];
struct Edge
{
int des,w;
}ed1,ed2;
vector<Edge>vec[5005];
int prim()
{
for(int i=2;i<=n;i++)
dis[i]=inf;//初始化:各点到树的距离为无穷大
int now=1;//默认从1开始建树
for(int i=0;i<vec[1].size();i++)
dis[vec[1][i].des]=min(vec[1][i].w,dis[vec[1][i].des]);
//更新:此时树中有1个元素1,于是各点到树的距离即为到1的距离
for(int i=2;i<=n;i++)
{
vis[now]=1;
int minn=inf;
int index=0;
for(int j=2;j<=n;j++)
{
if(dis[j]<minn&&!vis[j])
{
minn=dis[j];
index=j;
}
}//遍历未被访问的各点,找到距离树最近的点
if(!index) return -1;//如果各点到树的距离均为无穷大,无法生成MST,返回-1
sum+=minn;//加上路径
now=index;//新的元素加入树
for(int j=0;j<vec[now].size();j++)
{
if(vec[now][j].w<dis[vec[now][j].des])
dis[vec[now][j].des]=vec[now][j].w;
//遍历新的元素和其余各点的距离,更新各点到树的最小距离
}
}
return sum;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b,len;
scanf("%d%d%d",&a,&b,&len);
ed1.des=a,ed2.des=b,ed1.w=ed2.w=len;
vec[a].push_back(ed2);
vec[b].push_back(ed1);
}
int ans=prim();
if(ans==-1) cout<<"There is no minimum spanning tree";
else cout<<ans;
return 0;
}
#include
using namespace std;
int n,e,i;
int F[1501];
struct Edge
{
int from;
int to;
int w;
}edge[1501];
bool cmp(Edge x,Edge y)
{
return x.w<y.w;
}
int find(int x)
{
if(F[x]==x) return F[x];
else return F[x]=find(F[x]);
}
bool fun(int a,int b)
{
int x=find(a);
int y=find(b);
if(x!=y)
{
F[y]=x;
return true;
}
return false;
}
int main()
{
scanf("%d%d",&n,&e)
int total=0,cnt=0;
for(i=0;i<e;i++)
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].w);
for(i=0;i<n;i++) F[i]=i;
sort(edge,edge+e,cmp);
for(i=0;i<e;i++)
{
if(fun(edge[i].from,edge[i].to))
{
total+=edge[i].w;
cnt++;
}
if(cnt==n-1) break;
}
if(cnt==n-1) printf("%d\n",total);
else cout<<"There is no minimum spanning tree."<<endl;
return 0;
}
设 G为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1 到 n,请设计算法,计算图 G 中 1, n 间的最长路径。
//45ms / 3.10MB / 892B C++14 (GCC 9) O2
#include
using namespace std;
queue<int>q;
int n,m;
int maxn[1510],mark[1510],ind[1510];
//maxn:到当前结点之前的最长路
//mark:标记“在路径上”
//ind:记录每个结点的入度
struct Edge
{
int from;
int to;
int w;
}edge[50010];
vector<Edge>vec[50010];//vec为Edge型的,在已知起点时可直接通过这个调用出边权和终点
void topo_sort()//拓扑排序
{
for (int i=1;i<=n;i++)
if (ind[i]==0)
q.push(i);//先将所有入度为0 的结点放入队列
while(q.size())
{
int now=q.front();//每次取出队首元素
q.pop();
for(int j=0;j<vec[now].size();j++)//遍历队首元素指向的所有结点
{
ind[vec[now][j].to]--;//去掉当前结点的同时,它指向的所有结点入度减1
if(mark[now])//在路径上
{
if(maxn[vec[now][j].to]<maxn[now]+vec[now][j].w)
maxn[vec[now][j].to]=maxn[now]+vec[now][j].w;
//如果from之前的最长路加上边权大于之前获得的to之前的最长路,就更新一下
mark[vec[now][j].to]=1;//标记终点在路径上
}
if(!ind[vec[now][j].to]) //删边操作之后终点的入度变为0,则将其压入队列
q.push(vec[now][j].to);
}
}
}
int main()
{
int i;
cin>>n>>m;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].w);
vec[edge[i].from].push_back(edge[i]);
ind[edge[i].to]++;
}
maxn[n]=-1;
mark[1]=1;//标记起点(1)在路径上
topo_sort();
cout<<maxn[n];
return 0;
}
#include
using namespace std;
#define INF 0x3ffffff
struct Node
{
int v,l;//一条路的尾结点,该路的长度
};
int n,e,from,to;
vector<Node> v[1001];
int dis[1001];
int path[1001];
int visit[1001];
void Dijkstra(int from)
{
fill(dis,dis + 1001,INF);
dis[from] = 0;
for(int i = 0;i < n;i ++)
{
int u = -1,minx = INF;
for(int j = 0;j < n;j ++)
{
if(visit[j] == 0 && dis[j] < minx)
{
minx = dis[j];
u = j;
}
}
if(u == -1) break;
visit[u] = 1;
for (int j = 0; j < v[u].size(); j++)
{
int x = v[u][j].v;
if (visit[x] == 0 && dis[u] + v[u][j].l < dis[x])
{
dis[x] = dis[u] + v[u][j].l;
path[x] = u;
}
}
}
}
int main()
{
cin >> n >> e;
for (int i = 0; i < e / 2; i++)
{
int a, b, c;
cin >> a >> b >> c;
v[a].push_back(Node{b, c});
v[b].push_back(Node{a, c});
}
cin >> from >> to;
if (from == to)
{
printf("%d-->%d:0",from,from);
return 0;
}
Dijkstra(from);
vector<int> ve;
int x = to;
while (x != from)
{
ve.push_back(x);
x = path[x];
}
cout << from;
for (int i = ve.size() - 1; i >= 0; i--)
cout << "-->" << ve[i];
cout << ":" << dis[to];
}
单调队列优化:
将常规版本的Dijkstra 中每个结点遍历所有相邻结点找到距离最近的这一步用堆优化,每次直接从小根堆中直接取出顶点,可以将时间复杂度降到O(VlogV)。
// 309ms / 7.68MB / 1.02KB C++14 (GCC 9) O2
#include
using namespace std;
const int N=1e5+10;
int n,m,s;
int dis[N],vis[N];
struct Node
{
int to,w;
bool operator < (const Node& x) const
{
return w>x.w;
}
};
vector<Node> vec[N];
priority_queue<Node>q;
//默认大根堆(从头取数据从大到小),运算符重载后现在为小根堆
void Dijkstra()
{
memset(dis,0x3f,sizeof(dis));//距离初始化为无穷大
dis[s]=0;
Node now;
now.to=s,now.w=0;
q.push(now);//起点入队
while(!q.empty())
{
int next=q.top().to;//取出队顶元素(距离最小的)
q.pop();
if(vis[next]) continue;//已经访问过了就下一个
vis[next]=1;//标记已经访问过
for(int i=0;i<vec[next].size();i++)//遍历当前结点相邻的所有结点
{
if(vec[next][i].w+dis[next]<dis[vec[next][i].to])//松弛操作
{
dis[vec[next][i].to]=vec[next][i].w+dis[next];
now.to=vec[next][i].to;
now.w=dis[vec[next][i].to];
q.push(now);
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Node no;
no.to=b;
no.w=c;
vec[a].push_back(no);
}
Dijkstra();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
给出一个N个顶点M条边的无向无权图,顶点编号为1-N。问从顶点1开始,到其他每个点的最短路有几条。
// 1:50ms / 3.21MB / 863B C++14 (GCC 9) O2
// 2:48ms / 3.13MB / 877B C++14 (GCC 9) O2
#include
using namespace std;
const int mod=100003,N=1000010;
int n,m,ans[N],minn[N],vis[N];
struct edge
{
int a,b;
}e[N*2];
vector<int>vec[N];
queue<int>q;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void SPFA(int start)
{
minn[start]=0,ans[start]=1,vis[start]=1;
q.push(start);
int now;
while(q.size())
{
now=q.front();
q.pop();
for(int i=0;i<vec[now].size();i++)
{
if(!vis[vec[now][i]])
{
vis[vec[now][i]]=1;
if(minn[vec[now][i]]>minn[now]+1)
minn[vec[now][i]]=minn[now]+1;
q.push(vec[now][i]);
}
if(minn[vec[now][i]]==minn[now]+1)
ans[vec[now][i]]=(ans[vec[now][i]]+ans[now])%mod;
}
}
}
int main()
{
memset(minn,127,sizeof(minn));
n=read(),m=read();
for(int i=0;i<m;i++)
{
int x,y;
x=read(),y=read();
if(x==y) continue;
vec[x].push_back(y);
vec[y].push_back(x);
}
SPFA(1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}
#include
using namespace std;
#define N 1000
int n,m,x,y,z,posx=-1,posy=-1,max1;
int maps[N][N];
int path[N][N];
int pre[N];
void f(int x,int y)
{
int k=path[x][y];
if(k==-1){//找不到更近的
pre[y]=x;
return;
}
f(k,y);
f(x,k);
}
void print(int x,int y)
{
if(x==y)
{
cout<<x;
return;
}
print(x,pre[y]);
cout<<"->"<<y;
return;
}
int main()
{
memset(path,-1,sizeof(path));
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j) maps[i][j]=0x3ffffff;
for(int i=1;i<=m;i++)
{
cin>>x>>y>>z;
if(maps[x][y]>z) maps[x][y]=z;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(maps[i][j]>maps[i][k]+maps[k][j])
{
maps[i][j]=maps[i][k]+maps[k][j];
path[i][j]=k;
}
int t=2;
while(t--)
{
cin>>x>>y;
if(x==y) cout<<x<<"->"<<y<<":0"<<endl;
else
{
if(maps[x][y]==0x3ffffff)
cout<<x<<"->"<<y<<":-1"<<endl;
else
{
memset(pre,0,sizeof(pre));
f(x,y);
print(x,y);
cout<<":"<<maps[x][y]<<endl;
}
}
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(maps[i][j]!=0x3ffffff&&maps[i][j]>max1)
{
max1=maps[i][j];
posx=i;
posy=j;
}
memset(pre,0,sizeof(pre));
if(posx!=-1&&posy!=-1)
{
f(posx,posy);
print(posx,posy);
cout<<":"<<maps[posx][posy]<<endl;
}
else cout<<endl;
}
#include
#include
#include
using namespace std;
const int N=5020;
const int R=200010;
int n,r;
int dis[R],vis[R],ver[R],nex[R],val[R][2],head[R],tot=0;
queue<int>q;
int read()
{
int sum=0,fg=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')fg=-1;c=getchar();}
while(c>='0'&&c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*fg;
}
void add1(int x,int y,int z)
{
//edge[++tot].nxt=head[x],edge[tot].to=y,edge[tot].dis=z,head[x]=tot;
nex[++tot]=head[x],ver[tot]=y,dis[tot]=z,head[x]=tot;
}
/*void spfa(int start)
{
memset(val,0x7f,sizeof(val));
vis[start]=1,val[start][0]=0;
q.push(start);
while(!q.empty())
{
int now=q.front();
vis[now]=0;
q.pop();
for(int i=head[now];i;i=nex[i])
{
int to=ver[i];
if(val[now][0]+dis[i]val[now][0]+dis[i]&&val[now][0]+dis[i]>val[to][0])
{
val[to][1]=val[now][0]+dis[i];
if(!vis[to]) vis[to]=1,q.push(to);
}
if(val[to][1]>val[now][1]+dis[i])
{
val[to][1]=val[now][1]+dis[i];
if(!vis[to]) vis[to]=1,q.push(to);
}
}
}
}*/
void spfa(int s)
{
memset(val,0x7f,sizeof(val));
q.push(s);vis[s]=1;
val[s][0]=0;
while(!q.empty())
{
int u=q.front();
vis[u]=0;
q.pop();
for(int i=head[u];i;i=nex[i])
{
int v=ver[i];
if(val[v][0]>val[u][0]+dis[i])
{
val[v][1]=val[v][0];
val[v][0]=val[u][0]+dis[i];
if(!vis[v]) vis[v]=1,q.push(v);
}
if(val[v][1]>val[u][0]+dis[i]&&val[u][0]+dis[i]>val[v][0])
{
val[v][1]=val[u][0]+dis[i];
if(!vis[v]) vis[v]=1,q.push(v);
}
if(val[v][1]>val[u][1]+dis[i])
{
val[v][1]=val[u][1]+dis[i];
if(!vis[v]) vis[v]=1,q.push(v);
}
}
}
}
int main()
{
int x,y,z;
n=read();r=read();
for(int i=1;i<=r;i++)
{
x=read(),y=read(),z=read();
add1(x,y,z);add1(y,x,z);
}
spfa(n);
printf("%d\n",val[1][1]);
}
负环判断
#include
using namespace std;
const int N=10010;
int T,n,m;
int head[N],ver[N],nex[N],tot,vis[N],cnt[N],val[N],dis[N];
queue<int>q;
void add(int x,int y,int z)
{
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,val[tot]=z;
if(z>=0) ver[++tot]=x,nex[tot]=head[y],head[y]=tot,val[tot]=z;
}
void init()
{
tot=0;
memset(head,0,sizeof(head));
memset(ver,0,sizeof(ver));
memset(nex,0,sizeof(nex));
memset(vis,0,sizeof(vis));
memset(val,0,sizeof(val));
memset(cnt,0,sizeof(cnt));
memset(dis,0x3f,sizeof(dis));
while(!q.empty()) q.pop();
}
bool spfa()
{
vis[1]=1,dis[1]=0;
q.push(1);
while(q.size())
{
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[now];i;i=nex[i])
{
int to=ver[i];
if(dis[now]+val[i]<dis[to])
{
dis[to]=dis[now]+val[i];
if(!vis[to])
{
cnt[to]=cnt[now]+1;
if(cnt[to]>=n) return true;
vis[to]=1,q.push(to);
}
}
}
}
return false;
}
int main()
{
cin>>T;
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
if(spfa()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
#include
using namespace std;
const int N=520;
int n,m,e,tot,ans;
int mp[N][N],vis[N],match[N];
bool dfs(int x)
{
for(int i=1;i<=m;i++)
{
if(!mp[x][i]||vis[i]) continue;
vis[i]=1;
if(!match[i]||dfs(match[i]))
{
match[i]=x;
return true;
}
}
return false;
}
int main()
{
cin>>n>>m>>e;
for(int i=1;i<=e;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x][y]=1;
}
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
cout<<ans;
}
欧拉路径:欧拉路是指从图中任意一个点开始到图中任意一个点结束的路径,并且图中每条边通过的且只通过一次。
欧拉回路:欧拉回路是指起点和终点相同的欧拉路。
对于无向图,所有边都是连通的
(1)存在欧拉路径的充分必要条件:度数为奇数的点只能是0个或者2个
(2)存在欧拉回路的充分必要条件:度数为奇数的只能是0个
2对于有向图,所有边都是连通的
(1)存在欧拉路径的充分必要条件:要么所有点的出度均等于入度, 要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)
(2)存在欧拉回路的充分必要条件:所有点的出度均等于入度
求有向图字典序最小的欧拉路径。
#include
using namespace std;
const int N=100010;
int n,m,start=1;
int ind[N],outd[N],p[N];
vector<int>vec[N];
stack<int>st;
void dfs(int now)
{
for(int i=p[now];p[now]<vec[now].size();i++)
{
p[now]++;
//cout<<"p[now]:"<
dfs(vec[now][i]);
}
st.push(now);
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int from,to;
scanf("%d%d",&from,&to);
vec[from].push_back(to);
ind[to]++;
outd[from]++;
}
int flag=0;
for(int i=1;i<=n;i++)
{
sort(vec[i].begin(),vec[i].end());
//cout<
if(ind[i]==outd[i]) continue;
//cout<
else if(ind[i]==outd[i]+1) flag++;
else if(ind[i]==outd[i]-1) start=i,flag--;
else
{
cout<<"No";
return 0;
}
}
if(flag!=0)
{
cout<<"No";
return 0;
}
dfs(start);
while(st.size())
cout<<st.top()<<' ',st.pop();
return 0;
}