别问为什么没发树型dp和状压dp,因为我不是负责这块的,所以就做了一些例题略微了解了一下,没有发的必要,下面的图论是我负责的,先放一点比较经典的题目,也是雨巨拉的例题,后面应该会按题型发更多的图论(等这个入门班的笔记完结后)。
板子题:链式前向星+堆优化dij(复杂度:O((n+m)logm )
链式前向星详解:深度理解链式前向星ACdreamer-CSDN博客链式前向星(其实就是静态链表)
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define int long long
#define ll long long
#define pint pair<int,int>
#define mod 998244353
#define INF 0x3f3f3f3f
struct node{
int to,val,ne;
};
node mp[20010];
int head[1010];
int dis[1010];
int visit[1010];
int pos=0;
int n,m,s,en;
void addedge(int a,int b,int val){
mp[pos].ne=head[a];
head[a]=pos;
mp[pos].to=b;
mp[pos].val=val;
pos++;
}
void dij(int s,int en){
priority_queue<pint>q;
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty()){
pint t=q.top();
q.pop();
if(visit[t.se]==1){
continue;
}
visit[t.se]=1;
for(int i=head[t.se];i!=-1;i=mp[i].ne){
if(mp[i].val+dis[t.se]<dis[mp[i].to]){
dis[mp[i].to]=mp[i].val+dis[t.se];
//优先队列默认从大到小,改成负数就不用重写比较函数了
q.push(make_pair(-dis[mp[i].to],mp[i].to));
}
}
}
}
signed main(){
memset(head,-1,sizeof(head));
memset(visit,0,sizeof(visit));
cin>>n>>m>>s>>en;
for(int i=0;i<=n;i++){
dis[i]=INF;
}
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
addedge(a,b,c);
addedge(b,a,c);
}
dij(s,en);
if(dis[en]==INF){
cout<<-1<<endl;
return 0;
}
cout<<dis[en]<<endl;
return 0;
}
板子题,最小生成树(堆优化prim+链式前向星)
#include <bits/stdc++.h>
using namespace std;
struct node{
int to,ne,val;
};
node edge[1000010];
int head[100010];
int cnt=0;
void addedge(int a,int b,int val){
edge[++cnt].ne=head[a];
edge[cnt].val=val;
edge[cnt].to=b;
head[a]=cnt;
}
struct node2{
int a,val;
bool operator < (const node2 &a)const{
return this -> val > a.val;
}
};
priority_queue<node2>q;
int dis[100010];
int visit[100010];
void prim(){
node2 tem;
tem.a=1;
tem.val=0;
dis[1]=0;
q.push(tem);
while(!q.empty()){
tem=q.top();
q.pop();
cout<<tem.a<<endl;
if(visit[tem.a]==1){
continue;
}
visit[tem.a]=1;
for(int i=head[tem.a];i!=-1;i=edge[i].ne){
if(visit[edge[i].to]==1){
continue;
}
if(edge[i].val<dis[edge[i].to]){
dis[edge[i].to]=edge[i].val;
tem.a=edge[i].to;
tem.val=dis[edge[i].to];
q.push(tem);
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
memset(head,-1,sizeof(head));
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
addedge(a,b,c);
addedge(b,a,c);
}
prim();
int ans=0;
for(int i=1;i<=n;i++){
ans+=dis[i];
}
cout<<ans<<endl;
return 0;
}
经典问题了属于是,我们如果按照题目要求去想的话会发现很难写(因为不是字典序最小问题),所以我们采用经典反向建图,问题就转化成逆字典序最大,算是图论的一种经典策略,涉及到顺序问题的正着不好想就试一下反向建图。然后就求出这个图的字典序最大的拓扑排序然后反向输出就行了。
又有个地方要注意:链式前向星记录时,多组数据除了要初始化head和du以外,还要把cnt(代表当前存到第几个位置)也初始化才行,这里wa了好几发,呜呜呜。
#include <bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(0), cin.tie(0)
struct node{
int to,ne;
};
node edge[100001];
int du[100001];
int head[100001];
int cnt=0;
void addedge(int a,int b){
edge[cnt].ne=head[a];
edge[cnt].to=b;
head[a]=cnt;
cnt++;
}
priority_queue<int>q;
vector<int>ans;
int main(){
fast;
int t;
cin>>t;