图论相关题目

PAT1003紧急情况

在这里插入图片描述

#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
int n,m,s,t;//节点数目,边数目,起始点,终止点
int g[N][N];//记录边权值
bool visit[N];
int w[N];  //每个节点救援队的数量
int dis[N],route_sum[N],weight_sum[N]; // dis[i]表示起始点到i号点的最短路距离
                                       // route_sum[i]表示起始点到i号点的路线数目
                                       // weight_sum[i]表示起始点到i号点的救援队的数量集合
void dijkstra()
{
    dis[s] = 0;
    route_sum[s] = 1;
    weight_sum[s] = w[s];
    
    for(int i=0;i<n;i++){//循环n次每一次把一个点放进visit集合中
        
        //然后选出一个没加入visit中的dis值最小的点
        int tt = -1;
        for(int j=0;j<n;j++){
            if(!visit[j] && (tt==-1 || dis[j] < dis[tt])) tt = j;
        }
        visit[tt] = true;
        
        for(int j=0;j<n;j++){
            if(dis[j] > dis[tt] + g[tt][j]){
                dis[j] = dis[tt] + g[tt][j];
                route_sum[j] = route_sum[tt];
                weight_sum[j] = weight_sum[tt] + w[j];
            }
            else if(dis[j]==(dis[tt]+g[tt][j])){
                route_sum[j] += route_sum[tt];
                weight_sum[j] = max(weight_sum[j],weight_sum[tt]+w[j]);
            }
        }
        
        
    }
}

                                     
int main()
{
    memset(g,0x3f,sizeof g);
    memset(dis,0x3f,sizeof dis);
    cin >> n >> m >> s >> t;
    for(int i=0;i<n;i++) cin >> w[i];
    while(m--){
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b] = min(g[a][b],c); //防止有重复边输入,如果有重复遍的话只需要保存一个最小值就好了
        g[b][a] = min(g[b][a],c);
    }
    dijkstra();
    cout << route_sum[t] << " " << weight_sum[t] << endl;
    return 0;
}

旅行计划

在这里插入图片描述

#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int N = 510;
int n,m,s,d;
int g[N][N],c[N][N];
int dis[N],cost[N];  // cost[i]表示到i号点的花费距离
int pre[N];          // pre[i]表示i号节点是由哪个节点来到这里的
bool st[N];

int main()
{
    memset(g,0x3f,sizeof g);
    memset(c,0x3f,sizeof c);
    memset(pre,-1,sizeof pre);
    cin >> n >> m >> s >> d;
    while(m--){
        int a,b,x,y;
        cin >> a >> b >> x >> y;
        g[a][b] = g[b][a] = min(g[a][b],x);
        c[a][b] = c[b][a] = min(c[a][b],y);
    }
    
    memset(dis,0x3f,sizeof dis);
    memset(cost,0x3f,sizeof cost);
    dis[s] = 0;
    cost[s] = 0;
    for(int i=0;i<n;i++){
        int t = -1;
        for(int j=0;j<n;j++){
            if(!st[j] && (t==-1 || dis[j] < dis[t])) t = j;
        }
        st[t] = true;
        
        for(int j=0;j<n;j++){
            if(dis[j] > dis[t]+g[t][j]){
                dis[j] = dis[t] + g[t][j];
                cost[j] = cost[t] + c[t][j];
                pre[j] = t;
            }
            else if(dis[j]==(dis[t]+g[t][j])){
                if((cost[t]+c[t][j]) < cost[j]){
                    pre[j] = t;
                    cost[j] = cost[t] + c[t][j];
                }
            }
        }
    }
    vector<int> res;
    for(int i=d;i!=-1;i=pre[i]) res.push_back(i);
    for(int i=res.size()-1;i>=0;i--) cout << res[i] << " ";
    cout << dis[d] << " " << cost[d] << endl;
    return 0;
    
}

团伙头目

在这里插入图片描述

#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1010;
int n,k; 
map<string,vector<pair<string,int>>> g; //存储一个节点链接几个对象,以及每条边的权值
map<string,int> total;  //每个节点和相邻节点的边的总值,仅仅是和相邻节点的边,不是整个连通块的
map<string,bool> st;    //这个节点是否搜索过

//dfs寻找联通块的数量
//nodes记录连通块中的节点值
int dfs(string ver, vector<string>& nodes)
{
    st[ver] = true;
    nodes.push_back(ver);
    
    int sum = 0;
    for(auto next_node : g[ver]){
        sum += next_node.second;
        if(!st[next_node.first]) sum += dfs(next_node.first,nodes);
    }
    return sum;
}

int main()
{
    cin >> n >> k;
    //n是边的数目
    while(n--){
        string a,b;
        int t;
        cin >> a >> b >> t;
        g[a].push_back({b,t});
        g[b].push_back({a,t});
        total[a] += t;
        total[b] += t;
    }
    
    vector<pair<string,int>> res;  //每个帮派的头目名字以及节点数量
    for(auto item:total){
        string ver = item.first;
        vector<string> nodes;
        int sum = dfs(ver,nodes)/2;
        
        if(nodes.size()>2 && sum > k )
        {
            string boss = nodes[0];
            for(string node:nodes){
                if(total[boss] < total[node]) boss = node;
            }
            res.push_back({boss,nodes.size()});
        }
    }
    sort(res.begin(),res.end());
    cout << res.size() << endl;
    for(auto item:res){
        cout << item.first << " " << item.second << endl;
    }
    return 0;
}

条条大路通罗马

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
const int N = 210;
int n,k;
string city[N];
map<string,int> mp;  //把每个城市名字影射成一个数字
int w[N];    //城市权值
int g[N][N];

bool st[N];
int dis[N],route_num[N],cost[N],node_num[N],pre[N];
//到i号节点的最短距离, 路线数量, 最高花费(即最高幸福感),最小节点数目, 前一个节点
void dijkstra()
{
    memset(dis,0x3f,sizeof dis);
    dis[1] = 0;
    route_num[1] = 1;
    //初始城市不算所以不用node_num[1] = 1
    
    for(int i=0;i<n;i++){
        int t = -1;
        for(int j=1;j<=n;j++){
            if(!st[j] && (t==-1 || dis[j] < dis[t])) t = j;
        }
        st[t] = true;
        
        for(int j=1;j<=n;j++){
            if(dis[j] > dis[t]+g[t][j]){
                dis[j] = dis[t] + g[t][j];
                route_num[j] = route_num[t];
                cost[j] = cost[t] + w[j];
                node_num[j] = node_num[t] + 1;
                pre[j] = t;
            }
            else if(dis[j]==(dis[t]+g[t][j])){
                route_num[j] += route_num[t];
                if(cost[j] < cost[t]+w[j]){
                    cost[j] = cost[t] + w[j];
                    node_num[j] = node_num[t] + 1;
                    pre[j] = t;
                }
                else if(cost[j]==(cost[t]+w[j])){
                    if(node_num[j] > (node_num[t]+1)){
                        node_num[j] = node_num[t] + 1;
                        pre[j] = t;
                    }
                }
            }
        }
    }
    
}

int main()
{
    cin >> n >> k >> city[1];
    mp[city[1]] = 1;
    w[1] = 0;  //初始城市权值为0
    
    for(int i=2;i<=n;i++){
        cin >> city[i] >> w[i];
        mp[city[i]] = i;
    }
    
    memset(g,0x3f,sizeof g);
    while(k--){
        string a,b;
        int num;
        cin >> a >> b >> num;
        g[mp[a]][mp[b]] = min(g[mp[a]][mp[b]],num);
        g[mp[b]][mp[a]] = min(g[mp[b]][mp[a]],num);
    }
    dijkstra();
    int t = mp["ROM"];
    cout << route_num[t] << " " << dis[t] << " " << cost[t] << " " << cost[t]/node_num[t] << endl;
    
    vector<int> res;
    for(int i=t;i!=0;i=pre[i]) res.push_back(i);
    cout << city[res[res.size()-1]];
    for(int i=res.size()-2;i>=0;i--) cout << "->" << city[res[i]];
    
    return 0;
}

在线地图

在这里插入图片描述

#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int N = 510;
int dis1[N],time1[N];      //第一种方案先比较距离再比较时间
int time2[N],crossing[N];  //第二种方案先比较时间,再比较路口数量

int n,m,s,t;
int d1[N][N],d2[N][N];  //每条道路的距离以及时间
int pre[N];
bool st[N];

void dijkstra1()
{
    memset(dis1,0x3f,sizeof dis1);
    memset(time1,0x3f,sizeof time1);
    memset(st,0,sizeof st);
    dis1[s] = 0;
    time1[s] = 0;
    
    for(int i=0;i<n;i++){
        int t = -1;
        
        for(int j=0;j<n;j++){
            if(!st[j] && (t==-1 || dis1[j] < dis1[t] )) t = j;
        }
        st[t] = true;

        for(int j=0;j<n;j++){
            if(dis1[j] > (dis1[t] + d1[t][j])){
                dis1[j] = dis1[t] + d1[t][j];
                time1[j] = time1[t] + d2[t][j];
                pre[j] = t;
            }
            
            else if(dis1[j]==(dis1[t]+d1[t][j]))
            {
                if(time1[j] > (time1[t] + d2[t][j])){
                    time1[j] = time1[t] + d2[t][j];
                    pre[j] = t;
                }
            }
            
        }
    }
}

void dijkstra2()
{
    memset(time2,0x3f,sizeof time2);
    memset(crossing,0x3f,sizeof crossing);
    memset(st,0,sizeof st);
    memset(pre,-1,sizeof pre);
    time2[s] = 0;
    crossing[s] = 0;
    
    for(int i=0;i<n;i++){
        int t = -1;
        for(int j = 0; j < n; j++){
            if(!st[j] && (t==-1 || time2[j] < time2[t])) t = j;
        }
        st[t] = true;

        
        for(int j=0;j<n;j++){
            if(time2[j] > (time2[t]+d2[t][j])){
                time2[j] = time2[t] + d2[t][j];
                crossing[j] = crossing[t] + 1;
                pre[j] = t;
            }
            
            else if(time2[j] == (time2[t] + d2[t][j])){
                if(crossing[j] > (crossing[t]+1)){
                    crossing[j] = crossing[t] + 1;
                    pre[j] = t;
                }
            }
            
        }
        
    }
}

int main()
{
    memset(d1,0x3f,sizeof d1);
    memset(d2,0x3f,sizeof d2);
    cin >> n >> m;  //路口以及街道数量,路口编号0~n-1
    while(m--){
        int v1,v2,one_way,length,cost_time;
        cin >> v1 >> v2 >> one_way >> length >> cost_time;
        d1[v1][v2] = min(d1[v1][v2],length);
        d2[v1][v2] = min(d2[v1][v2],cost_time);
        if(!one_way){
            d1[v2][v1] = min(d2[v2][v1],length);
            d2[v2][v1] = min(d2[v2][v1],cost_time);
        }
    }
    cin >> s >> t;  //起始地与目的地
    
    vector<int> path1;
    dijkstra1();
    
    for(int i=t;i!=s;i=pre[i]) path1.push_back(i);
    path1.push_back(s);

    
    vector<int> path2;
    dijkstra2();
    for(int i=t;i!=s;i=pre[i]) path2.push_back(i);
    path2.push_back(s);

    
    if(path1 != path2){
        printf("Distance = %d: ",dis1[t]);
        cout << path1[path1.size()-1];
        for(int i=path1.size()-2;i>=0;i--) cout << " -> " << path1[i];
        cout << endl;
        printf("Time = %d: ",time2[t]);
        cout << path2[path2.size()-1];
        for(int i=path2.size()-2;i>=0;i--) cout << " -> " << path2[i];
    }
    else{
        printf("Distance = %d; Time = %d: ",dis1[t],time2[t]);
        cout << path1[path1.size()-1];
        for(int i=path1.size()-2;i>=0;i--) cout << " -> " << path1[i];
    }
    return 0;
    
    
}

哈密顿回路

在这里插入图片描述

#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210;
bool g[N][N];
int n,m;
int nodes[N]; //记录每次询问的路径
bool st[N]; //记录每个节点是否都被访问过


//判断哈密顿路径问题考虑四种情况
//1.如果最后一个节点与第一个节点不是同一个节点返回false
//2.哈密顿路径要求n个节点都被走一次,所以总路线节点数不是n+1的话肯定不可以
//3.如果1~n号节点中有没有被访问的则返回false
//4.如果路径中有两个节点之间没有边返回false

bool check(int node_num)
{
    if(nodes[0] != nodes[node_num-1]) return false; //如果最后一个节点与第一个节点不是同一个节点返回false
    if(node_num != n+1) return false;  //哈密顿路径要求n个节点都被走一次,所以总路线节点数不是n+1的话肯定不可以
    //如果1~n号节点中有没有被访问的则返回false
    memset(st,0,sizeof st);
    for(int i=0;i<n;i++){
        st[nodes[i]] = true;
    }
    for(int i=1;i<=n;i++){
        if(st[i]==false) return false;
    }
    //如果路径中有两个节点之间没有边返回false
    for(int i=0;i<node_num-1;i++){
        if(g[nodes[i]][nodes[i+1]] == false) return false;
    }
    
    return true;
}

int main()
{
    cin >> n >> m;
    while(m--)
    {
        int a,b;
        cin >> a >> b;
        g[a][b] = g[b][a] = true;
    }
    int k;
    cin >> k;
    while(k--)
    {
        int cnt;
        cin >> cnt;
        for(int i=0;i<cnt;i++) cin >> nodes[i];
        if(check(cnt)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

欧拉路径

在这里插入图片描述

/*
如果一个连通图的所有顶点的度数都为偶数,
那么这个连通图具有欧拉回路,且这个图被称为欧拉图。

如果一个连通图中有两个顶点的度数为奇数,其他顶点的度数为偶数,
那么所有欧拉路径都从其中一个度数为奇数的顶点开始,并在另一个度数为奇数的顶点结束。
具有欧拉路径但不具有欧拉回路的图被称为半欧拉图。
*/
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
bool g[N][N];
int d[N];  //记录每个点的度数
//节点编号是1~n
int n,m;
bool st[N];
int res = 0;
void dfs(int u)
{
    res++;
    st[u] = true;
    for(int i=1;i<=n;i++){
        if(!st[i] && g[u][i]) dfs(i);
    }
}

int main()
{
    memset(st,0,sizeof st);
    cin >> n >> m;
    while(m--)
    {
        int a,b;
        cin >> a >> b;
        g[a][b] = g[b][a] = true;
        d[a]++,d[b]++;
    }
    dfs(1);
    int degree_odd = 0;
    for(int i=1;i<=n;i++){
        if(d[i]%2) degree_odd++;
    }
    for(int i=1;i<=n;i++) cout << d[i] << " ";
    cout << endl;
    if(res==n){
        if(degree_odd==0) puts("Eulerian");
        else if(degree_odd==2) puts("Semi-Eulerian");
        else puts("Non-Eulerian");
    }
    else puts("Non-Eulerian");
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新城里的旧少年^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值