【数据结构机试】图
存储 & 访问
struct node{
int to, d;
};
vector<node> e[N];
for(auto x : e[u]) {
...
}
欧拉图、哈密尔顿图判定
https://www.cnblogs.com/re0acm/p/17521363.html
要在判断欧拉图的同时找出一种遍历所有边的方式。
注意:必须先遍历完子图,再把当前的边加入,然后逆序输出。
点击查看代码
#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;
}
这题需要求出所有的最短路径,再依次判定。只贪心做是错的
点击查看代码
#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;
}
这题可以bfs or dfs
最小生成树
搞清楚 \(prim\)、 \(kruscal\) 两种算法