【数据结构机试】图

存储 & 访问

struct node{
  int to, d;
};
vector<node> e[N];

for(auto x : e[u]) {
  ...
}

欧拉图、哈密尔顿图判定

https://www.cnblogs.com/re0acm/p/17521363.html

例1
https://www.luogu.com.cn/problem/P2731

要在判断欧拉图的同时找出一种遍历所有边的方式。

注意:必须先遍历完子图,再把当前的边加入,然后逆序输出。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
using namespace std;
const int N = 500 + 10;
int m, n = 500, u, v;
int rd[N], path[N][N];
int start = 1;
int cnt, ans[N];

void dfs(int u) {
    for(int i = 1; i <= 500; i++) {
        if(path[u][i]) {
            path[u][i]--;
            path[i][u]--;  //  有向图删掉
            dfs(i);
        }
    }
    ans[++cnt] = u;
}

int main() {  
    ios::sync_with_stdio(false);
    cin >> m;
    for(int i = 1; i <= m; i++) {
        cin >> u >> v;
        path[u][v]++; path[v][u]++;
        rd[u]++; rd[v]++;
    }
    for(int i = 1; i <= 500; i++) {
        if(rd[i] % 2) {
            start = i;
            break;
        }
    }
    dfs(start);
    for(int i = cnt; i >= 1; i--) cout << ans[i] << endl;
    return 0;
}


拓扑排序

每次找到一个入度为0的点,去掉从它出发的弧,递归处理。

最短路

dijk、floyd

问题分类:

  • 求最短路
  • 求最短路条数
  • 输出最短路径
  • 在求最短路的同时要求其他条件

放个模板:

#include<bits/stdc++.h>  //dijkstra 模板 
#define ll long long
const int N = 100005,M = 200005,inf = 0x3f3f3f3f, mod = 1e9 + 7;
using namespace std;
int n,m,s;
bool ok[N];
int head[M],cnt;
ll dis[N], Cnt[N];
struct edge{
	int v,next,to;
};
edge e[M];  //边的数量 
struct node{
	ll dis;
	int pos;
	bool operator < (const node &x) const{
		return x.dis<dis;
	}
};
priority_queue<node>pq;

void init(){
	cnt=0;
	memset(ok,0,sizeof(ok));
	memset(head,-1,sizeof(head));
}

inline void add(int u,int v,int d){
	cnt++;
	e[cnt].to=v;
	e[cnt].v=d;
	e[cnt].next=head[u];
	head[u]=cnt;
}

void dijk(){
	dis[s]=0;
	Cnt[s] = 1;
	pq.push((node){0,s});
	while(!pq.empty()){
		node tem=pq.top();
		pq.pop();
		int x=tem.pos,d=tem.dis;
		if(ok[x]){
			continue;
		}
		ok[x]=1;
		for(int i=head[x];~i;i=e[i].next){
			int y=e[i].to;
			if(dis[y]>dis[x]+e[i].v){
				dis[y]=dis[x]+e[i].v;
				Cnt[y] = 0;
				if(!ok[y]){
					pq.push((node){dis[y],y});
				}
			}
			if(dis[y] == dis[x] + e[i].v) {
				Cnt[y] = (Cnt[y] + Cnt[x]) % mod;
			}
		}
	}
}

int main(){
	while(scanf("%d%d%d",&n,&m,&s)==3){
	init();
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	for(int i=1,u,v,d;i<=m;i++){
		scanf("%d%d%d",&u,&v,&d);
		add(u,v,d);
	}
	dijk();
	for(int i=1;i<=n;i++){
		if(i<n) printf("%lld ",dis[i]);
		else printf("%lld\n",dis[i]);
	}
	}
	return 0;
} 

例1
1018 Public Bike Management

这题需要求出所有的最短路径,再依次判定。只贪心做是错的

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 500 + 50;
int n, m, a[N], st, en, Hold;
struct Node{
	int id;
	ll dis;
	vector<int> Path;
	bool operator < (const Node &aa) const{
		return dis > aa.dis;
	}
};
bool vis[N];
ll dis[N];
struct node{
	int to, d;
};
vector<node> e[N];
ll ans = 1e18, ans2 = 1e18;
vector<int> an;

void check(vector<int> v) {
	ll Need = 0, Collect = 0;
	for(auto x : v) {
		// cout << x << ' ';
		if(x == st) continue;
		x = a[x];
		if(x >= Hold) Collect += x - Hold;
		else {
			ll tmp = Hold - x;
			if(Collect >= tmp) {
				Collect -= tmp;
				continue;
			}
			else {
				tmp -= Collect;
				Collect = 0;
				Need += tmp;
			}
		}
	}
	if(Need < ans) {
		ans = Need; ans2 = Collect;
		an = v;
	}
	else if(Need == ans && Collect < ans2) {
		ans2 = Collect;
		an = v;
	}
}

void dijk(int s) {
	for(int i = 0; i <= n; i++) {
		vis[i] = 0;
		dis[i] = 1e18;
	}
	priority_queue<Node> Q;
	Q.push({s, 0, {s}});
	dis[s] = 0;
	while(!Q.empty()) {
		Node now = Q.top();
		Q.pop();
		int u = now.id;
		// if(vis[u] && u != en) continue;
		if(dis[u] < now.dis) continue;
		if(u == en) {
			check(now.Path);
			continue;
		}
		// cout << u << ' ' << now.fa << endl; ////
		for(auto v : e[u]) {
			if(dis[v.to] >= dis[u] + v.d) {
				dis[v.to] = dis[u] + v.d;
				auto tem = now.Path; tem.push_back(v.to);
				Q.push({v.to, dis[v.to], tem});
			}
		}
	}
}

int main () {
	cin >> Hold >> n >> en >> m;
	st = 0;  Hold /= 2;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1, u, v, w; i <= m; i++) {
		cin >> u >> v >> w;
		e[u].push_back((node){v, w});
		e[v].push_back((node){u, w});
	}
	dijk(st);
	cout << ans << ' ';
	for(int i = 0; i < an.size(); i++) {
		if(i == 0) cout << an[i];
		else cout << "->" << an[i];
	}
	cout << ' ' << ans2 << endl;
    return 0;
}

例2
1131 Subway Map

这题可以bfs or dfs

最小生成树

搞清楚 \(prim\)\(kruscal\) 两种算法

posted @ 2023-08-31 18:18  starlightlmy  阅读(3)  评论(0编辑  收藏  举报