c_pat_哈密顿回路 & 最大点集 & 是否是旅行商路径 & 欧拉路径 & 最深的根(邻接矩阵存图)

Hamiltonian Cycle

哈密顿回路问题是找到一个包含图中每个顶点的简单回路。你需要做的是判断给定路径是否为哈密顿回路。

充分条件
从任意起点出发,都具有以下性质的回路成为哈密顿回路:

  • 起点=终点
  • 每个待判序列给出的结点个数等于n+1,否则,必然经过某一个结点多次
  • 1~n个结点都能被访问

坑:写则顶点编号从1N,暗地里却设为12N...

#include<bits/stdc++.h>
using namespace std;
const int N=205;
int n,m,Q,a[2*N],g[N][N];

bool chk(int sz) {
    if (sz!=n+1 || a[0]!=a[sz-1]) return false;
    bool vis[N]; memset(vis, false, sizeof vis);
    for (int i=1; i<sz; i++) {
        if (!g[a[i-1]][a[i]]) return false;
        vis[a[i]]=1;
    } 
    for (int i=1; i<=n; i++) if (!vis[i])
        return false;
    return true;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m;
    for (int i=0; i<m; i++) {
        int u,v; cin>>u>>v;
        g[u][v]=g[v][u]=1;
    }
    cin>>Q;
    while (Q--) {
        int sz; cin>>sz;
        for (int i=0; i<sz; i++) cin>>a[i];
        cout << (chk(sz) ? "YES" : "NO")<<'\n';
    } 
    return 0;
}

Maximal Clique

在一个无向图中,如果一个顶点子集满足子集内的任意两个不同顶点之间都是相连的,那么这个顶点子集就被称为一个团。
如果一个团不能通过加入某个新的顶点来扩展成一个更大的团,那么该团就被称为最大团。
现在,你需要判断给定顶点子集能否构成一个最大团。

思路

#include<bits/stdc++.h>
using namespace std;
const int N=205;
int n,m,a[N],g[N][N];
bool is_clique(int sz) {
    for (int i=0; i<sz-1; i++)
    for (int j=i+1; j<sz; j++) if (!g[a[i]][a[j]])
        return false;
    return true;
} 
bool is_maximal(int sz) {
    bool in_a[N]; memset(in_a, false, sizeof in_a);
    for (int i=0; i<sz; i++) in_a[a[i]]=true;

    for (int i=1; i<=n; i++) if (!in_a[i]) { //如果不在a中的点能和a中所有点相连,则不是最大点集;换句话说,只要有一个不在a中的顶点不和a中所有点相连,则认定这个点集是最大的
        bool is_allconn=true;
        for (int j=0; j<sz; j++) if (!g[i][a[j]]) {
            is_allconn=false;
            break;
        }
        if (is_allconn) return false;
    }
    return true;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m;
    for (int i=0; i<m; i++) {
        int u,v; cin>>u>>v;
        g[u][v]=g[v][u]=true;
    }
    int q; cin>>q;
    while (q--) {
        int k; cin>>k;
        for (int i=0; i<k; i++) cin>>a[i];
        if (is_clique(k)) {
            cout<<(is_maximal(k) ? "Yes":"Not Maximal")<<'\n';
        } else {
            cout<<"Not a Clique\n";
        }
    }
    return 0;
}

Travelling Salesman Problem

请你从给定的路径列表中找到最接近旅行商问题的解的路径。
输出 Shortest Dist(X) = TotalDist,X 是最接近旅行商问题解决方案的回路编号,TotalDist 是其总距离。

思路
tsp问题就是求解哈密顿回路

#include<bits/stdc++.h>
using namespace std;
const int N=205, inf=0x3f3f3f3f;
int n,m,a[N],g[N][N];
int get_cost(vector<int>& v) {
    int n=v.size(), cost=0;
    for (int i=1; i<v.size(); i++) cost+=g[v[i-1]][v[i]]; 
    return cost;
}
bool is_all_conn(vector<int>& v) {
    for (int i=1; i<v.size(); i++) if (g[v[i-1]][v[i]]<0)
        return false;
    return true;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m; memset(g, -inf, sizeof g);
    for (int i=0; i<m; i++) {
        int u,v,w; cin>>u>>v>>w;
        g[u][v]=g[v][u]=w;
    }
    int q, minCost=inf, minCostIdx=0; cin>>q;
    for (int c=1; c<=q; c++) {
        int k; cin>>k;
        vector<int> v(k);
        unordered_set<int> st;
        for (int i=0; i<k; i++) cin>>v[i], st.insert(v[i]);
        int conn=is_all_conn(v);
        if (st.size()<n || v.front()!=v.back() || !conn) {
            int cost=get_cost(v);
            if (!conn) printf("Path %d: NA (Not a TS cycle)\n", c);
            else printf("Path %d: %d (Not a TS cycle)\n", c, cost);
        } else {
            int cost=get_cost(v);
            if (v.size()==n+1) {
                printf("Path %d: %d (TS simple cycle)\n", c, cost);
            } else printf("Path %d: %d (TS cycle)\n", c, cost);
            if (cost<minCost) minCost=cost, minCostIdx=c;
        }
    }
    printf("Shortest Dist(%d) = %d", minCostIdx, minCost);
    return 0;
}

Eulerian Path

事实证明,如果一个连通图的所有顶点的度数都为偶数,那么这个连通图具有欧拉回路,且这个图被称为欧拉图。
如果一个连通图中有两个顶点的度数为奇数,其他顶点的度数为偶数,那么所有欧拉路径都从其中一个度数为奇数的顶点开始,并在另一个度数为奇数的顶点结束。具有欧拉路径但不具有欧拉回路的图被称为半欧拉图。
现在,给定一个无向图,请你判断它是欧拉图、半欧拉图还是非欧拉图。

模拟即可

#include<bits/stdc++.h>
using namespace std;
const int N=505;
vector<int> g[N];
int d[N], vis[N];
int dfs(int u) {
    int c=1;
    vis[u]=1;
    for (int v : g[u]) if (!vis[v]) {
        c+=dfs(v);
    }
    return c;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n,m; cin>>n>>m;
    for (int i=0; i<m; i++) {
        int u,v; cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
        d[u]++, d[v]++;
    }
    int odd_degree=0;
    for (int i=1; i<=n; i++) if ((d[i]&1)==1) 
        odd_degree++;
    int c=dfs(1);
    for (int i=1; i<=n; i++) {
        cout<<d[i];
        if (i!=n) cout<<' ';
    }
    cout<<'\n';
    if (c==n) {
        if (odd_degree==0) cout<<"Eulerian\n";
        else if (odd_degree==2) cout<<"Semi-Eulerian\n";
        else cout<<"Non-Eulerian\n";
    } else {
        cout<<"Non-Eulerian\n";
    }
    return 0;
}

Deepest Root

一个无环连通图可以被视作一个树。树的高度取决于所选取的根节点。现在,你要找到可以使得树的高度最大的根节点。
思路
并查集检查树的合法性+暴力算最大深度maxd,并找到深度为maxd的结点

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int fa[N];
vector<int> g[N];
int find(int u) {
    return fa[u]==u ? u : fa[u]=find(fa[u]);
}
void merge(int u, int v) {
    int fu=find(u), fv=find(v);
    if (fu!=fv)  fa[fu]=fv;
}
int get_dep(int u, int fa) {
    int d=1;
    for (int v : g[u]) if (v!=fa) {
        d=max(d, get_dep(v,u)+1);
    }
    return d;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n; cin>>n;
    for (int i=1; i<=n; i++) fa[i]=i;
    for (int i=1; i<n; i++) {
        int u,v; cin>>u>>v;
        g[u].push_back(v), g[v].push_back(u);
        merge(u,v);
    }
    int cnt=0;
    for (int i=1; i<=n; i++) if (fa[i]==i) {
        cnt++;
    }
    if (cnt>1) {
        printf("Error: %d components\n",cnt);
    } else {
        vector<int> v;
        int maxd=0;
        //for (int i=1; i<=n; i++) maxd=max(maxd, get_dep(i,-1));
        //for (int i=1; i<=n; i++) if (get_dep(i,-1)==maxd) v.push_back(i);
        for (int i=1; i<=n; i++) { //为什么这样会高效一些
            int d=get_dep(i,-1);
            if (d>maxd) {
                maxd=d;
                v.clear();
                v.push_back(i);
            } else if (d==maxd) {
                v.push_back(i);
            }
        }
        sort(v.begin(), v.end());
        for (int droot : v) printf("%d\n",droot);
    }
    return 0;
}
posted @ 2020-09-28 16:54  童年の波鞋  阅读(213)  评论(0编辑  收藏  举报