图论模板

来源:互联网 发布:linux清空文件夹内容 编辑:程序博客网 时间:2024/06/05 19:14
//TheWaySoFar图论模板一.最短路1.Dijkstra算法(邻接矩阵/邻接表)2.SPFA3.Bellman-ford4.folyd5.次短路6.K短路(Astart + SPFA)二.分图1.染色体判二分2.匈牙利算法三.拓扑排序1.模板(邻接表/邻接矩阵)四.并查集(简单略)五.最小生成树1.prim(邻接表/邻接矩阵)六.网络流1.FF2.EK(紫书略)3.Dinic七.杂1.强连通分量tarjan算法2.连通图的割点3.欧拉回路(Fleury算法)4.哈密顿回路(回溯)5.判断图的可图性(Havel-Hakimi定理)-----------------------------------------------------------------------------------以下模板多数的头模板#include <iostream>#include <cstdio>#include <sstream>#include <cstring>#include <map>#include <set>#include <vector>#include <stack>#include <queue>#include <algorithm>#include <cmath>#define LL long long#define INF 0x3f3f3f3f#define maxn 1024#define Pair pair<int, int>#define mem(a, b) memset(a, b, sizeof(a))#define _  ios_base::sync_with_stdio(0),cin.tie(0)//freopen("1.txt", "r", stdin);using namespace std;---------------------------------------------------------------------------------一:最短路1.dijstra算法/* void dijkstra(int s)  无向图   邻接表 + 优先队列   参数 s : 出发点    */代码:typedef pair<int, int> P;struct edge{    int to, cost;};int V;vector<edge> G[maxn];int d[maxn];void dijkstra(int s){    priority_queue<Pair, vector<Pair>, greater<Pair> > que;    fill(d, d + V + 2, INF);    d[s] = 0;    que.push(Pair(0, s));    while (!que.empty()) {        Pair p = que.top();        que.pop();        int v = p.second;        if (d[v] < p.first) continue;//到v点的距离如果已经被更新 这无须执行以下操作        for (int i = 0; i < G[v].size(); ++i) {            edge e= G[v][i];            if (d[e.to] > d[v] +e.cost) {                d[e.to] = d[v] + e.cost;                que.push(P(d[e.to], e.to));            }        }    }}int main(){    int m;    cin >> V >> m;    for (int i = 0; i < m; ++i) {        int from, to, cost;        cin >> from >> to >> cost;        edge var;        var.to = to;        var.cost = cost;        G[from].push_back(var);        var.to = from;        G[to].push_back(var);//无向图    }    dijkstra(1);    for (int i = 1; i <= V; ++i)        cout << d[i] << endl;   //到i的距离    return 0;}/* dijstra算法    邻接矩阵*/int map[MAXV][MAXV],d[MAXV];bool vis[MAXV];                    //是否已经访问拿过int n,m,x;void dijkstra(){    int i,j,v,mi;    for(i=1;i<=n;i++){        vis[i]=0;        d[i]=map[x][i];    }    for(i=1;i<=n;i++){        mi=inf;        for(j=1;j<=n;j++)            if(!vis[j] && d[j]<mi){ //寻找没有访问过且距离已被更新为最小的点                v=j;                mi=d[j];            }            vis[v]=1;            for(j=1;j<=n;j++){                if(!vis[j] && map[v][j]+d[v]<d[j])                    d[j]=map[v][j]+d[v];            }    }    for(int i=1;i<=n;i++)        cout<<d[i]<<endl;}int main(){    freopen("d.txt","r",stdin);    int i,a,b,c,j;    while(~scanf("%d%d%d",&n,&m,&x)){        for(i=1;i<=n;i++){            for(j=1;j<=n;j++)                if(i!=j) map[i][j]=inf;                else map[i][j]=0;        }        for(i=1;i<=m;i++){/            scanf("%d%d%d",&a,&b,&c);            map[a][b]=c;            map[b][a]=c;        }        dijkstra();    }    return 0;}---------------------------------------------------------------------------------------------2.SPFA算法/*  bool SPFA(int source) 返回是否存在负环    参数:source:出发点    queue + 邻接表*/const int maxn = 5000;typedef struct node{    int to, cost;}edge;vector<edge> v[maxn];int in_sum[maxn];      //每个点的入队次数int in_que[maxn];      //是否在队列里面int n, m, d[maxn];bool SPFA(int source){    deque<int> q;    for (int i = 1; i <= n; ++i) {        d[i] = i == source ? 0 : INF;    }    q.push_back(source);    in_sum[source]++;    in_que[source] = 1;    while (!q.empty()) {        int curr = q.front();        q.pop_front();        in_que[curr] = 0;        for (int i = 0; i < v[curr].size(); ++i) {            int to = v[curr][i].to;            if (d[curr] < INF && d[to] > d[curr] + v[curr][i].cost) {                d[to] = d[curr] + v[curr][i].cost;                if (in_que[to] == 0) {                    in_que[to] = 1;                    if(++in_sum[to] == n)     //入队次数等于n则存在负环                        return false;                    }                     if(!q.empty())                    {                        if(d[to] > d[q.front()]) q.push_back(to);                        else q.push_front(to);                    }else q.push_back(to);            }        }    }    return true;}-------------------------------------------------------------------------------3.Bellman-ford/*    bool Bellman_Ford() 返回是否存在负环*/typedef struct Edge //边{    int u, v;    int cost;}Edge;Edge edge[N];int dis[N], pre[N];bool Bellman_Ford(){    for(int i = 1; i <= nodenum; ++i) //初始化        dis[i] = (i == original ? 0 : MAX);    for(int i = 1; i <= nodenum - 1; ++i)        for(int j = 1; j <= edgenum; ++j)            if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)            {                dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;                pre[edge[j].v] = edge[j].u;            }            bool flag = 1; //判断是否含有负权回路            for(int i = 1; i <= edgenum; ++i)                if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)                {                    flag = 0;                    break;                }                return flag;}------------------------------------------------------------------------------------4.folyd/*    O(n^3);*//*---算法区---*/for(k=1; k<=n; k++)    for(i=1; i<=n; i++)        for(j=1; j<=n; j++)        {            if(d[i][k]+d[k][j]<d[i][j])                d[i][j]=d[i][k]+d[k][j];        }/*---算法区---*/-------------------------------------------------------------------------------------5.次短路/*见白书*/----------------------------------------------------------------------------------6.K短路/*A*算法:使用估值函数来进行搜索,f(n)=g(n)+h(n),    其中f(n)表示状态起点经过状态n到状态终点的估值,    g(n)为状态起点到状态n的距离值,    h(n)为状态n到状态终点的距离值。SPFA的意义在于反着求其t点到各点的最短距离*/#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <queue>using namespace std;const int maxn=1005;const int maxe=100005;struct State{    int f;  // f=g+dis dis表示当前点到终点的最短路径,即之前的预处理    int g; //g表示到当前点的路径长度    int u;    bool operator<(const State b)const{        if(f==b.f)return g>b.g;        return f>b.f;    }};struct Edge{    int v;    int w;    int ne;}edge[maxe],reedge[maxe];int head[maxn],rehead[maxn];int dis[maxn],vis[maxn];int n,m;int cot;int s,t,k;void init(){    cot=0;    //cot代表边的id  每条边的id都不相同    memset(head,-1,sizeof(head));    memset(rehead,-1,sizeof(rehead));}void addedge(int u,int v,int w){    edge[cot].v=v;    edge[cot].w=w;    edge[cot].ne=head[u];//记录上一次u的id是多少 这样方便遍历  初始值为-1    head[u]=cot;//head[u]  给这个u标记上独一无二的id    reedge[cot].v=u;    reedge[cot].w=w;    reedge[cot].ne=rehead[v];    rehead[v]=cot++;}void SPFA(){    queue<int>q;    memset(vis,0,sizeof(vis));    memset(dis,-1,sizeof(dis));    int u,v;    q.push(t);    vis[t]=true;//vis表示当前点是否在队列    dis[t]=0;    while(!q.empty()){        u=q.front();        q.pop();      //rehead[u] 是u最后一次出现的id  reedge[i].ne  代表第i次出现的边上一次出现的id        for(int i=rehead[u];~i;i=reedge[i].ne){  //~i取反 当i为-1时正好取反为0 退出for            v=reedge[i].v;            if(dis[v]>dis[u]+reedge[i].w||dis[v]==-1){                dis[v]=dis[u]+reedge[i].w;                if(!vis[v]){                    q.push(v);                    vis[v]=true;                }            }        }        vis[u]=false;    }}int Astart(){    if(s==t)k++;    if(dis[s]==-1)return -1;    int cnt=0;    priority_queue<State>q; // 优先队列    State a,b;    a.g=0;    a.u=s;    a.f=a.g+dis[a.u];    q.push(a);    while(!q.empty()){        b=q.top();        q.pop();        if(b.u==t){            cnt++;            //printf("%d %d %d %d\n",b.f,b.g,b.u,dis[b.u]);            if(cnt==k)return b.g;        }        for(int i=head[b.u];~i;i=edge[i].ne){            a.g=b.g+edge[i].w;            a.u=edge[i].v;            a.f=a.g+dis[a.u];            q.push(a);        }    }    return -1;}int main(){    int u,v,w;    while(scanf("%d %d",&n,&m)==2){        init();        for(int i=0;i<m;i++){            scanf("%d %d %d",&u,&v,&w);            addedge(u,v,w);        }        scanf("%d %d %d",&s,&t,&k);        SPFA();        /*        for(int i=1;i<=n;i++){            printf("%d:%d\n",i,dis[i]);        }        */        printf("%d\n",Astart());    }    return 0;}----------------------------------------------------------------------------------二.分图1.染色体判二分/* 利用BFS */bool f = true;for (int i = 1; i <= n; ++i){    //if(vis[i]) == 1;    if(!vis[i]) {        vis[i] = 1;        que.push(i);    }    while (!que.empty()) {        int x = que.front();        que.pop();        for (int i = 0; i < vec[x].size(); ++i) {            int temp = vec[x][i];            if (vis[temp] == vis[x]) {                f = false;                break;            }            if(vis[temp] == 0) {                vis[temp] = 3 - vis[x];                que.push(temp);            }        }    }}--------------------------------------------------------------------------------------2.匈牙利算法/*  bool dfs(int u) 返回是否匹配成功    邻接矩阵模板*/constint MAXN=1000;int uN,vN;  //u,v数目int g[MAXN][MAXN];//编号是0~n-1的int linker[MAXN];bool used[MAXN];bool dfs(int u){     int v;     for(v=0;v<vN;v++)        if(g[u][v]&&!used[v])        {            used[v]=true;            if(linker[v]==-1||dfs(linker[v]))            {                linker[v]=u;                return true;            }        }   return false;}int hungary(){int res=0;int u;    memset(linker,-1,sizeof(linker));    for(u=0;u<uN;u++)    {        memset(used,0,sizeof(used));        if(dfs(u))  res++;    }return res;}----------------------------------------------------------------------------------------------------/* 邻接表模板匈牙利算法 参数:x:当前匹配的人*/#define maxn 1024#define Pair pair<int, int>#define mem(a, b) memset(a, b, sizeof(a))#define _  ios_base::sync_with_stdio(0),cin.tie(0)using namespace std;vector<int> vec[maxn];bool used[maxn];bool line[maxn][maxn];int find(int x){    for (int i = 0; i < vec[x].size(); ++i) {int v = vec[x][i];        if (!used[v]) {            used[v] = true;            if (obj[v] == 0 && find(obj[v])) {               obj[v] = x;                return true;            }        }    }    return false;}int main(){    int ans = 0;    for (int i = 1; i <= n; ++i) {        memset(used, 0, sizeof(used));        if(find(i)) ans += 1;    }}--------------------------------------------------------------------------------------------三.拓扑排序/*    int topsort() 返回是可以排序:0是有环,1是yes    优先队列*/int n, m;vector<int> g[maxn];  //图vector<int> ans;  //答案int in[maxn]; //入度int topsort(){    int sum = 0;    priority_queue<int, vector<int>, greater<int> > que;   //每次弹出最小的 按照字典序记录答案    for (int i = 1; i <= n; ++i) {        if (in[i] == 0) que.push(i);  //把入度为0的入队    }    while ( !que.empty() ) {        int x = que.top();        sum++;                 //记录入度为0的点数量        ans.push_back(x);   //记录答案        que.pop();        for (int j = 0; j < g[x].size(); ++j) {            int v = g[x][j];            if (--in[v] == 0) {        //入度减去1 是否已经为零                que.push(v);          //为零则入队            }        }    }    if (sum < n) return 0;   度为0的数量小于总的点数 有环存在    return 1;}---------------------------------------------------------------------------------------------五.最小生成树1.prim(邻接表/邻接矩阵)/*    void prim(int s)    参数*/using namespace std;int g[maxn][maxn];int n, m, ans;int vis[maxn], pre[maxn], pos, lowcost[maxn];priority_queue<Pair, vector<Pair>, greater<Pair> > que;void prim(int s)      //由某点开始{    int ans = 0;    for (int i = 1; i <= n; ++i) {        lowcost[i] = g[s][i];             //  到此点的距离        pre[i] = 1;                         //此点的前驱,        que.push(Pair(g[s][i], i));    }    lowcost[s] = 0;    vis[s] = -1;    int mini = INF, pos = -1;    while (!que.empty()) {        mini = INF;        Pair v = que.top();        que.pop();//如果这个点被访问continue注:这也是最后优先队列还有很多点 却可以退出的原因, 因为其都被标-1        if(vis[v.second] == -1) continue;        if(g[pre[v.second]][v.second]) printf("%d %d\n", pre[v.second], v.second); //输出搭建的边        ans += lowcost[v.second];        vis[v.second] = -1;        for (int j = 1; j <= n; ++j) {            if (vis[j] != -1 && g[pre[j]][j] > g[v.second][j]) {                lowcost[j] = g[v.second][j];     //更新到此点的距离                que.push(Pair(g[v.second][j], j));                pre[j] = v.second;            //更新此点的前区            }        }    }    //cout << ans << endl;   //输出总消费}--------------------------------------------------------------------------------//邻接表建图using namespace std;vector<Pair> vec[maxn];int lowcost[maxn], pre[maxn], vis[maxn];priority_queue<Pair, vector<Pair>, greater<Pair> > que;priority_queue<Pair, vector<Pair>, greater<Pair> > ans;int n, m, sum, MAX;void prim(){    mem(lowcost, INF);    for (int i =0; i < vec[1].size(); ++i) {        Pair temp = vec[1][i];        lowcost[temp.second] = temp.first;        pre[temp.second] = 1;        que.push(temp);    }    lowcost[1] = 0;    vis[1] = 1;    while (!que.empty()) {        Pair v = que.top();        que.pop();        if(vis[v.second]) continue;        sum += v.first;        MAX = max(MAX, v.first);        vis[v.second] = 1;        ans.push(Pair(pre[v.second], v.second));        for (int i = 0; i < vec[v.second].size(); ++i) {            Pair temp = vec[v.second][i];            if (!vis[temp.second] && temp.first < lowcost[temp.second]) {               lowcost[temp.second] = temp.first;               pre[temp.second] = v.second;               que.push(temp);            }        }    }    cout << MAX << endl;    cout << sum << endl;    while (!ans.empty()) {        cout << ans.top().first << " "  << ans.top().second << endl;        ans.pop();    }}------------------------------------------------------------------------------------------------六.网络流1.FF/*    int max_flow(int s,int t) 返回最大流量    参数: s:起点   t:终点    数组模拟邻接表建图*/#include <cstdio>#include <cstring>#include <iostream>#include <string>#include <algorithm>#include <map>#include <vector>using namespace std;const int N = 1100;const int INF = 0x3f3f3f3f;struct Node{    int to;//终点    int cap; //容量    int rev;  //反向边};vector<Node> v[N];bool used[N];void add_Node(int from,int to,int cap)  //重边情况不影响{    v[from].push_back((Node)    {        to,cap,v[to].size() //v[to].size()  因为接下来要把这条表插入v[to] 所以这里用v[to].size()                      //正好v[i][j],j是由下标0开始的,size条边就是其反向边    });    v[to].push_back((Node)    {        from,0,v[from].size()-1   //反过来要减一也很好理解了    });}int dfs(int s,int t,int f){    if(s==t)        return f;    used[s]=true;    for(int i=0; i<v[s].size(); i++)    {        Node &tmp = v[s][i];  //注意 这个地方是为了改变v[s][i]的大小 所以加了引用        if(used[tmp.to]==false && tmp.cap>0)        {            int d=dfs(tmp.to,t,min(f,tmp.cap));            if(d>0)            {                tmp.cap-=d;                v[tmp.to][tmp.rev].cap+=d;                return d;            }        }    }    return 0;}int max_flow(int s,int t){    int flow=0;    for(;;)    {        memset(used,false,sizeof(used));        int f=dfs(s,t,INF);        if(f==0)            return flow;        flow+=f;    }}int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        memset(v,0,sizeof(v));        for(int i=0; i<n; i++)        {            int x,y,z;            scanf("%d%d%d",&x,&y,&z);            add_Node(x,y,z);        }        for (int i = 1; i <= m; ++i) {                cout << "   " << i << endl;            for (int j = 0; j < v[i].size(); ++j) {                cout << v[i][j].rev << endl;            }        }        printf("%d\n",max_flow(1,m));    }}-------------------------------------------------------------------------------------------------------3.Dinic/*    int Dinic(int s, int t) 返回最大流量    参数:s:开始节点 t:终止节点    数组模拟邻接表*///模板区#include <bits/stdc++.h>#define LL long long#define INF 0x3f3f3f3f#define maxn 210#define Pair pair<int, int>#define mem(a, b) memset(a, b, sizeof(a))using namespace std;int level[maxn];int d[maxn];int prev[maxn];int cnt;typedef struct node{    int v, cap;    int next;}edge;edge g[maxn<<1];void init(){    cnt = 0;    mem(prev, -1);    mem(g, 0);}void read_g(int u, int v, int cap){   g[cnt].v = v;   g[cnt].cap = cap;   g[cnt].next = prev[u];   prev[u] = cnt++;   g[cnt].v = u;   g[cnt].cap = 0;                 //逆向初始为0   g[cnt].next = prev[v];   prev[v] = cnt++;}int bfs(int s, int t){    memset(level, 0, sizeof level);    level[s] = 1;    queue<int> que;    que.push(s);    while (!que.empty()) {        int x = que.front();        que.pop();        if(x == t) return 1;        for (int i = prev[x]; i != -1; i = g[i].next) {            int v = g[i].v;            int f = g[i].cap;            if(!level[v] && f > 0) {                level[v] = level[x] + 1;                que.push(v);            }        }    }    return 0;}int dfs(int u, int t, int cap){    if(u == t) return cap;    int ret = 0;    for (int i = prev[u]; i != -1; i = g[i].next) {        int v = g[i].v;        int f = g[i].cap;        if(level[u]+1 == level[v] && f > 0) {            int mins = min(cap - ret, f);            f = dfs(v, t, mins);            g[i].cap -= f;            g[i^1].cap += f;            ret += f;            if(ret == cap) return ret;        }    }    return ret;}int Dinic(int s, int t) //Dinic{int ans = 0;while(bfs(s, t)) ans += dfs(s, t, INF);return ans;}//模板区int main(){    int a, b, c, N, M;    while (~scanf("%d%d", &N, &M)) {        init();        while (N--) {            scanf("%d%d%d", &a, &b, &c);            read_g(a, b, c);               /// 双向建图,逆向初始为0流量        }        cout << Dinic(1, M) << endl;    }    return 0;}---------------------------------------------------------------------------------------------------------1.强连通分量tarjan算法/*  int tarjan (int u) 以u为起点    有向图临街表建图    强连通分量解释: 子图中任意两点a,b a可以到达b, b可以到达a*/using namespace std;stack<int> stk;vector<int> vec[maxn];int low[maxn];int dfs[maxn];bool vis[maxn];int cnt;int n, m;void init(){    for (int i = 1 ; i <= n; ++i) {        vec[i].clear();        dfs[i] = 0;        low[i] = 0;        vis[i] = false;    }    cnt = 0;}int tarjan (int u)   //递归处理的点{    dfs[u] = low[u] = ++cnt; //时间线    stk.push(u);              //进栈    vis[u] = true;            //标记是否在栈中    for (int i = 0; i < vec[u].size(); ++i) {        int v = vec[u][i];        if(!dfs[v]) {          //如果没被访问过            tarjan(v);            low[u] = min(low[u], low[v]);  //比较谁是最小根        }        else if(vis[v]) {              //如果在栈中            low[u] = min(low[u], dfs[v]);  //判断最小根        }    }    if(low[u] == dfs[u]) {               //发现是整个强连通分量子树里的最小根        int temp;        do{            temp = stk.top();            printf("%d", temp);            vis[temp] = false;            stk.pop();        }while (u != temp);        cout << endl;    }    return 0;}int main(){    init();    cin >> n >> m;    for (int i = 1; i <= m; ++i) {        int a, b;        cin >> a >> b;        vec[a].push_back(b);    }    for (int i = 1; i <= n; ++i) {        //扫描所有的点        if(!dfs[i]) tarjan(i);    }    return 0;}----------------------------------------------------------------------------------------------------------2.连通图的割点/* void dfs(int now,int father,int depth){    参数:now:当前节点, father:当前节点的父节点, depth记录dfs标号    采用邻接表存储图,该算法的时间复杂度应与DFS相同,为O(V+E)*///WHITE:标未访问//GREY: 标访问到了,在处理中//BLACK: 标处理完毕。const int N = 110;const int WHITE = 0,GREY = 1,BLACK = 2; //标记值int map[N][N];int col[N],low[N],dep[N];//colorint n,m;bool tag[N];//标记点i是否割点//求0-1图的割点void dfs(int now,int father,int depth){    col[now] = GREY;  //相当于进栈    dep[now] = depth;    int child = 0;    for(int i=1;i<=n;i++){         //第i个邻接点        if(map[now][i]==0)continue;        if(i != father && col[i] == GREY)            low[now] = min(low[now], dep[i]);//low需要被初始化成大数        if(col[i] == WHITE){  // 这是now的子节点            dfs(i, now, depth+1);            child = child + 1;  //孩子的数量            low[now] = min(low[now], low[i]);            //割点: now是跟且有多个孩子 or now不是根且            if((now==1&&child>1)||(now!=1&&low[i]>=dep[now])) //now 不是根                tag[now] = 1;//注意:需要记录该割点增加几个联通分量的操作需要在这里cnt++        }    }    col[now] = BLACK;}void init(){    mem(map,0);    mem(col,0);    mem(tag,0);    mem(low[i], INF); //low应该被初始化成大值}int main(){    int a,b;    cin>>n>>m;    init();    for(int i=0;i<m;i++){        cin>>a>>b;        map[a][b] = map[b][a] = 1;//无向图    }    dfs(1,1,0);//dfs(root,root,0)的形式调用就行了    int ans=0;    for(int i=1;i<=n;i++)        if(tag[i])cout<<i<<' ';    cout<<endl;    system("pause");    return 0;}------------------------------------------------------------------------------3.欧拉回路(Fleury算法)/*  void fleury(int u)    参数:u 为起点    欧拉回路解释:图G中存在这样一条路径,使得它恰通过G中每条边一次,且该路径是一个圈*/stack<int> stk;int top;int n, m, s, t;int mp[maxn][maxn];void dfs(int x){    stk.push(x);    for (int i = 1; i <= n; ++i)        if(mp[x][i]) {            mp[x][i] = mp[i][x] = 0;  //删除次边            dfs(i);            break;        }}void fleury(int u){    int brige;    top = 0;    stk.push(u);    while (!stk.empty()) {        brige = 1;        int now = stk.top();        for (int i = 1; i <= n; ++i) //搜索一条边不是割边            if (mp[now][i]) {                brige = 0;                break;            }        if (brige) {    //如果没有点可以扩展, 输出并出栈            printf("%d ", now);            stk.pop();        }        else {          //否则继续搜索欧拉路径            stk.pop();            dfs(now);        }    }}int main(){    int x, y, deg, num;    mem(mp, 0);    scanf("%d%d", &n, &m);    for (int i = 1; i <= m; ++i) {        scanf("%d%d", &x, &y);        mp[x][y] = mp[y][x] = 1;    }    s = 1;  //开始点 如果所有点度数全为偶数那就从1开始搜    num = 0;    //记录度数为奇数的点的个数    for (int i = 1; i <= n; ++i) {        deg = 0;        for (int j = 1; j <= n; ++j)            deg += mp[i][j];       if(deg % 2 == 1) {            ++num;              //度数为奇数+1            s = i;        }    }    if(num == 0 || num == 2) {        //度数为奇数的点数量必须是0或者2        fleury(s);    }    else printf("no euler path\n");    return 0;}----------------------------------------------------------------------------------------4.哈密顿回路(回溯)/*  bool hcs(int s) 返回是否存在哈密顿回路    参数: s:起始点    邻接表 + dfs    时间复杂度 O(n)    哈密顿回路:由指定的起点前往指定的终点,途中经过所有其他节点且只经过一次     1.Dirac定理:设一个无向图中有 N 个节点,     若所有节点的度数都大于等于 N/2,     则汉密尔顿回路一定存在。*/vector<int> vec[maxn];int path[maxn];     //记录路径bool vis[maxn];     //是否被访问过bool link[maxn];    //记录其余点和起点是否直接相连                    //缺点是必须之前输入起点 补救是可以建立邻接矩阵存图int v, m;void print()        // 打印哈密顿回路{    for (int i = 1; i <= v; ++i) {        printf("%d ", path[i]);    }    printf("%d", path[1]);  //回路}bool hc(int u, int c) //u为上一个访问的 和 第c个点{    if (c > v) { //已访问v个顶点        if (link[u] == 1) return true;        else return false;    }    for (int i = 0; i < vec[u].size(); ++i) {        int child = vec[u][i];        if (!vis[child]) {            vis[child] = true;            path[c] = child;            if(hc(child, c + 1)) return true;            vis[child] = false;        }    }    return false;}bool hcs(int s){    mem(path, -1);    mem(vis, false);    vis[s] = true;  //起点为s    path[1] = s;    if (!hc(s, 2)) {        printf("no hamCycleStart\n");        return false;    }    print();    return true;}int main(){    int start;    scanf("%d%d%d", &v, &m, &start);  //顶点和边数    mem(link, false);    for (int i = 1; i <= v; ++i){        vec[i].clear();    }    for (int i = 1 ; i <= m; ++i) {        int a, b;        scanf("%d%d", &a, &b);        if(a == start) link[b] = true;        if(b == start) link[a] = true;        vec[a].push_back(b);        //无向图邻接表建图        vec[b].push_back(a);    }    hcs(start);    return 0;}-------------------------------------------------------------------------------------5.判断图的可图性/*    度序列:若把图 G 所有顶点的度数排成一个序列 S,则称 S 为图 G 的度序列    判定过程:(1)对当前数列排序,使其呈递减,    (2)从S【2】开始对其后S【1】个数字-1,    (3)一直循环直到当前序列出现负数(即不是可图的情况)或者当前序列全为0 (可图)时退出。*/int T, n;int in[maxn], x[maxn];int g[maxn][maxn];int main(){    _;    cin >> T;    while (T--) {        cin >> n;        for (int i = 1; i <= n; ++i) {            cin >> x[i];        }        mem(g, 0);        bool flag = true;        for (int i = 1; i <= n; ++i) {            int v = 0;            for (int j = 1; j <= n; ++j) {                if(i != j && x[j] && x[i]) {                    x[j]--;                    x[i]--;                    g[i][j] = 1;                    g[j][i] = 1;                }            }            if(x[i]) {                flag = false;                break;            }        }        if (flag) {            cout << "YES" <<endl;            for (int i = 1; i <= n; ++i) {                for (int j =1; j <= n; ++j) {                    if(j - 1) cout << " ";                    cout << g[i][j];                }                cout << endl;            }        }        else cout << "NO" << endl;        if(T) cout << endl;    }    return 0;}----------------------------------------------------------------------------------------待续.........

0 0
原创粉丝点击