中国邮路代码实现(纯粹的暴力)

本代码!!!!纯粹的暴力!!!!复杂度……反正很高……不适用于大数据!!!!

样例1(欧拉图):
7
10
1 2 4
1 3 1
1 4 3
1 7 4
2 4 5
3 4 3
4 7 2
5 6 2
5 7 10
6 7 7
样例2(非欧拉图):
7
10
1 2 1
1 6 3
1 7 2
2 3 1
3 4 4
3 7 2
4 7 3
4 5 2
5 6 1
6 7 3

样例一

样例二

/*难点:
1、对于非简单图,如何去储存它边和点的信息(要记录的元素有:点、多条边权、邻接点、度数,路径)
3、在连接奇点使其边偶点时使新增的边权最小
3、用fleury算法判读应该选取的边(即当有其他边可选时,不选割边)
*/
/*
解决方案
1、刚开始是想用一个结构体和几个数组来存的,后来想了想几个数组一把梭算了md
2、刚开始看着网上有个优化好像挺不错的,后来发现,我还是暴力递归写得舒服………舒服的一批
   即用Foloyd算法算出所有奇点之间的最短路,然后枚举选出奇点的完美匹配
3、每取一次变就判断取过该变所产生的图是否连通,可以直接用搜索解决;
*/
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1000000000
int E,V,sum,sta;    //边、点、路径总和、开始点
int C[1000][1000],A[1000][1000],G[1000][1000];  //记录连通边的边权,两点之间的最短长度,邻接矩阵
int P[1000][1000]={0};  //记录最短路路径
bool vis[1000];
int d[1000];
int sg[1000],ssg,cont[1000];       //额外开一个数组,用于储存奇点是哪个点,个数
//输入信息
void input(){
    ssg=0,sum=0,sta=0;
    //Foloyd算法的初始化过程
    for(int i = 0 ;i < 1000;i++)
     for(int j = 0;j < 1000;j++){
        G[i][j]=0;
        if(i == j)    A[i][j] = 0,C[i][j] = 0;
        else         A[i][j] = N,C[i][j] = N;
    }
    printf("请输入顶点个数:\n");
    scanf("%d",&V);
    printf("请输入边的条数:\n");
    scanf("%d",&E);
    int n=E,t=0;
    printf("请输入所有的邻接的两个点和他们的边:\n");
    while(n--){
        int a,b,l;
        scanf("%d %d %d",&a,&b,&l);      //相应的处理读到的信息
        d[a]++;             //a点度数加一
        d[b]++;             //b点度数加一
        G[b][a]++;          //邻接矩阵的初始化
        G[a][b]++;
        A[a][b] = l;        //Foloyd算法的初始化过程
        A[b][a] = l;
        C[a][b] = l;
        C[b][a] = l;
        sum+=l;             //权重
        //printf("d[%d]=%d 'd[%d]=%d\n",a,d[a],b,d[b]);
    }
    printf("请输入你的起始点:");
    scanf("%d",&sta);
    for(int i=1;i<=V;i++)//记录奇点的个数
        if(d[i]%2==1)
            sg[++ssg]=i;
}
bool connect(int op,int v){         //用于判断是否是连通图
    if(v==0)    return true;
    memset(vis,0,sizeof(vis));
    queue<int>q;
    q.push(op);
    vis[op]=1;
    int mm=1;
    while(!q.empty()){
        int node=q.front();
        for(int i=1;i<=V;i++){
            if(!vis[i]&&G[node][i]>0){
                vis[i]=1;
                mm++;
                q.push(i);
            }
        }
        q.pop();
    }
    //printf("连通点的个数:%d\n",mm);
    if(mm==v)           return true;
    else                return false;
}
//想了想还是决定用Foloyd算法,复杂度什么的,懒得考虑了。
void Foloyd(int k){
    if(k>V) return;
    for(int i = 1;i <= V;i++){
        for(int j = 1; j <= V; j++){
            if(A[i][j] >  A[i][k] + A[k][j]){
                P[i][j] = k;
                A[i][j] = A[i][k] + A[k][j];
            }
        }
    }
    Foloyd(++k);
}
int adde(int cn){//直接不计较复杂度的暴力递归。将奇点进行匹配得一个最小的
    int ans=N;
    if(cn<2)    return 0;       //奇点个数小于2,无需匹配。
    for(int i=1;i<=cn;i++){
        if(sg[i]!=0){
            for(int j=i+1;j<=cn;j++){
                if(sg[j]!=0){
                    int tem1=sg[i],tem2=sg[j];
                    sg[i]=0;
                    sg[j]=0;
                    if(ans>adde(cn-2)+A[tem1][tem2]){
                        cont[i]=tem2;       //第i个奇点匹配的奇点是第j个奇点
                        cont[j]=tem1;       //第j个奇点匹配的奇点是第i个奇点
                        ans=adde(cn-2)+A[tem1][tem2];
                    }
                    sg[i]=tem1;
                    sg[j]=tem2;
                }
            }
        }
    }
    return ans;
}
void addpath(int cn){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=cn;i++){
        if(!vis[sg[i]]){
            vis[sg[i]]=1;
            vis[cont[i]]=1;
            while(P[sg[i]][cont[i]]){
                //printf("is ok?%d %d\n",sg[i],cont[i]);
                int sss=cont[i];
                d[cont[i]]++;           //加边操作
                cont[i]=P[sg[i]][cont[i]];
                d[cont[i]]++;
                G[sss][cont[i]]++;G[cont[i]][sss]++;
                //printf("?????%d %d %d\n",sss,cont[i],sg[i]);
            }
            d[sg[i]]++;d[cont[i]]++;           //加边操作
            G[sg[i]][cont[i]]++;G[cont[i]][sg[i]]++;
        }
    }
}
int test(){    //计算当前图中点的个数
    int ss=0;
    for(int i=1;i<=V;i++)
        if(d[i]>0)
            ss++;
    //printf("est:%d\n",ss);
    return ss;
}
void Fleury(int sta){
    int i,cpn=0;
    int vi = sta; // v0e1v1…eivi已经选定
    printf("最优路径之一:\n");
    while(true)
    {
        // 找一条不是割边的边ei+1
        for(i = 1; i <= V; i++)
        {
            if (G[vi][i] > 0)
            {
                // 假设选定(vi,i)这条边
                G[vi][i]--;
                G[i][vi]--;
                d[i]--;d[vi]--;
                if(!connect(i,test()))      // 这里一定要传i,这是欲选择边的末端,它应该在连通图中
                {
                    G[vi][i]++;
                    G[i][vi]++;
                    d[i]++;d[vi]++;
                    continue;
                }
                // 选定(vi,i)这条边,打印路径
                if(cpn==0)
                printf("%d->%d",vi,i);
                else
                printf("->%d",i);
                cpn++;
                vi = i;
                break;
            }
        }
        if (i > V)
        {
            printf("\n");
            break; // 边找完了
        }
    }
}
int main(){
    input();
    if(!connect(sta,V)){
        printf("输入的图不是连通图\n");
        return 0;
    }
    Foloyd(1);
    sum+=adde(ssg);
    addpath(ssg);
    printf("最优巡回的总权重是:%d\n",sum);
    Fleury(sta);
    return 0;
}

总结:其实想了想,不该看网上那胡诌的想法的,搞得自己想的太多了,太复杂了。看看暴力是多么的优雅(虽然过不了题,但是写的开心)…
emm……不过算法还是要多学多写的,还是要尽量去优化的,不能一味的暴力。

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值