算法笔记第十章图

图的遍历

A1013

本题考察是连通块的计算以及如何分割一个点。

本题需要知道增加最少的边使图联通的数为连通块的数量减1。
对于无权图最好使用邻接表,直接用vector数组即可。

  1. 用dfs方法,每次碰到分割点时就直接返回,最后计算调用了几次dfs函数就有几个连通块,而所求答案就是连通块数减1.
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> G[N];
int n, m, k, currentPoint;
bool vis[N];
int father[N];
void dfs(int u)
{
    if(u == currentPoint) return;
    else
    {
        vis[u] = true;
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(vis[v] == false) dfs(v);
        }
    }
}
int DFSTrave()
{
    int num = 0;
    for(int i = 1; i <= n; i++)
    {
        if(i == currentPoint) continue;
        if(vis[i] == false)
        {
            dfs(i);
            num++;
        }
    }
    return num;
}
int main()
{
    int u, v;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    while(k--)
    {
        memset(vis, false ,sizeof(vis));
        scanf("%d", &currentPoint);
        printf("%d\n", DFSTrave() - 1);
    }
    return 0;
}
  1. 用并查集的方法,先将图读进去,读入隔离点后进行Union操作,如果u和v都不等于隔离点则将他们合并就相当于隔离了隔离点。最后记录总共读取了几个根节点就等于多少个连通块
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> G[N];
int n, m, k, currentPoint;
bool vis[N];
int father[N];
void init()
{
    for(int i = 0; i < n; i++)
    {
        father[i] = i;
        vis[i] = false;
    }
}
int findfather(int v)
{
    if(father[v] == v) return v;
    else
    {
        father[v] = findfather(father[v]);
        return father[v];
    }
}
void Union(int a, int b)
{
    int fa = findfather(a);
    int fb = findfather(b);
    if(fa != fb) father[fa] = fb;
}
int main()
{
    int u, v;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    while(k--)
    {
        init();
        scanf("%d", &currentPoint);
        for(int u = 1; u <= n; u++)
        {
            for(int j = 0; j < G[u].size(); j++)
            {
                int v = G[u][j];
                if(u != currentPoint && v != currentPoint)
                {
                    Union(u, v);
                }
            }
        }
        int num = 0;
        for(int i = 1; i <= n; i++)
        {
            if(i == currentPoint) continue;
            int fa_i = findfather(i);
            if(vis[fa_i] == false)
            {
                num++;
                vis[fa_i] = true;
            }
        }
        printf("%d\n", num - 1);
    }
    return 0;
}

A1021

所需数学知识:

  1. 求最深根结点集合时,对任意一个结点遍历得到的最深根结点集合一定属于所求集合
  2. 树的所有直径(最长深度的路路径)一定有公共区间或公共点
  3. 求最深根集合算法:先对任意结点进行遍历,得到最深根结合A,从A中任选一个集合再次遍历得到集合B。集合A和B的并即为所求

需要代码知识:

  1. 用并查集求连通分量
  2. 输出数组不重复元素
  3. dfs求最根节点集合

需要注意的点:

  1. block函数要赋初始值0
  2. 记得调用init函数来初始化并查集
  3. dfs中temp更新,ans在主函数跟新
  4. 因为是无向图在邻接表遍历的时候可能会出现遇到前驱的情况,所以要加入一个参数pre,跳过pre的情况
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, maxdepth;
vector<int> G[N];
vector<int> temp, ans;
int father[N];
bool isroot[N];
void init()
{
    for(int i = 1; i <= n; i++)
    {
        father[i] = i;
        isroot[i] = false;
    }
}
int findfather(int x)
{
    int a = x;
    while(x != father[x])
        x = father[x];
    while(a != father[a])
    {
        int z = a;
        a = father[a];
        father[z] = x;
    }
    return x;
}
void Union(int a, int b)
{
    int fa = findfather(a);
    int fb = findfather(b);
    if(fa != fb) father[fa] = fb;
}
int callblock()
{
    int block = 0;
    for(int i = 1; i <= n; i++)
    {
        isroot[findfather(i)] = true;
    }
    for(int i = 1; i <= n; i++)
        block+=isroot[i];
    return block;
}
void DFS(int u, int depth, int pre)
{
    if(depth > maxdepth)
    {
        maxdepth = depth;
        temp.clear();
        temp.push_back(u);
    }
    else if(depth == maxdepth)
    {
        temp.push_back(u);
    }
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(v == pre) continue;
        DFS(v, depth+1, u);
    }
}
int main()
{
    scanf("%d", &n);
    init();
    for(int i = 1; i < n; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        G[a].push_back(b);
        G[b].push_back(a);
        Union(a, b);
    }
    int block = callblock();
    if(block != 1) printf("Error: %d components", block);
    else
    {
        DFS(1, 1, -1);
        ans = temp;
        DFS(ans[0], 1, -1);
        for(int i = 0; i < temp.size(); i++)
        {
            ans.push_back(temp[i]);
        }
        sort(ans.begin(), ans.end());
        printf("%d\n", ans[0]);
        for(int i = 1; i < ans.size(); i++)
        {
            if(ans[i] != ans[i - 1]) printf("%d\n", ans[i]);
        }
    }
    return 0;
}

A1034

本题也是dfs遍历题目,但是需要处理字符串,首先需要建立字符串与数字的映射。在dfs中对每个结点访问时先判断是否成为head再对每条边进行访问,为了方式重复将边计算的情况每次将边加入后都要把边的权值设为0。最后建立map将结果存储。

需要注意n最大为2010,因为可能出现每个通话人都不一样的情况,所以要2*N。

#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int G[N][N];
int weight[N];
bool vis[N];
map<string,int> string2int;
map<int,string> int2string;
map<string,int> gang;
int n, k, numperson = 0;
int change(string str)
{
    if(string2int.find(str) != string2int.end())
        return string2int[str];
    else
    {
        string2int[str] = numperson;
        int2string[numperson] = str;
        return numperson++;
    }
}
void DFS(int nowvisit, int& head, int& number, int& totalvalue)
{
    if(weight[nowvisit] > weight[head])
        head = nowvisit;
    number++;
    vis[nowvisit] = true;
    for(int i = 0; i < n; i++)
    {
        if(G[nowvisit][i] > 0)
        {
            totalvalue+=G[nowvisit][i];
            G[nowvisit][i] = G[i][nowvisit] = 0;
            if(vis[i] == false)
            {
                DFS(i, head, number, totalvalue);
            }
        }
    }
}
int main()
{
    scanf("%d%d", &n, &k);
    string str1, str2;
    int value;
    for(int i = 0; i < n; i++)
    {
        cin >> str1 >> str2 >> value;
        int id1 = change(str1);
        int id2 = change(str2);
        weight[id1] += value;
        weight[id2] += value;
        G[id1][id2] += value;
        G[id2][id1] += value;
    }
    for(int i = 0; i < numperson; i++)
    {
        if(vis[i] == false)
        {
            int head = i, number = 0, totalvalue = 0;
            DFS(i, head, number, totalvalue);
            if(totalvalue > k && number > 2)
            {
                gang[int2string[head]] = number;
            }
        }
    }
    printf("%d\n", gang.size());
    map<string,int>::iterator it;
    for(it = gang.begin(); it != gang.end(); it++)
    {
        cout << it->first << " " << it->second << endl;
    }
    return 0;
}

A1076

一道带层数的bfs题,注意num是统计可以转发的数目,第一个不算,需要加入队列时num++。

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
struct node
{
    int v, layer;
};
vector<node> G[N];
bool inq[N] = {false};
int n, l;
int BFS(int s, int l)
{
    int num = 0;
    queue<node> q;
    node start;
    start.v = s;
    start.layer = 0;
    q.push(start);
    inq[start.v] = true;
    while(!q.empty())
    {
        node topNode = q.front();
        q.pop();
        int u = topNode.v;
        for(int i = 0; i < G[u].size(); i++)
        {
            node temp = G[u][i];
            temp.layer = topNode.layer + 1;
            if(inq[temp.v] == false && temp.layer <= l)
            {
                q.push(temp);
                num++;
                inq[temp.v] = true;
            }
        }
    }
    return num;
}
int main()
{
    int followNum, idfollow;
    node user;
    scanf("%d%d", &n, &l);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &followNum);
        for(int j = 0; j < followNum; j++)
        {
            user.v = i;
            scanf("%d", &idfollow);
            G[idfollow].push_back(user);
        }
    }
    int query, s;
    scanf("%d", &query);
    for(int i = 0; i < query; i++)
    {
        scanf("%d", &s);
        memset(inq, false, sizeof(inq));
        printf("%d\n", BFS(s, l));
    }
    return 0;
}

最短路径

A1003

本题要求最短路径的个数以及最多权值数,是一道模板题,用了dijkstra堆优化+dfs完成

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
struct node
{
    int v, dis;
    node(int _v, int _dis):v(_v),dis(_dis){}
    friend bool operator < (const node& a, const node& b)
    {
        return a.dis > b.dis;
    }
};
vector<node> Adj[N];
bool vis[N];
int dist[N];
int weight[N];
vector<int> pathtemp, path;
vector<int> pre[N];
int n, m, c1, c2;
void dijkstra(int st)
{
    fill(dist,dist+N, inf);
    memset(vis, false, sizeof(vis));
    dist[st] = 0;
    priority_queue<node> q;
    q.push(node(st, 0));
    //vis[st] = true;
    while(!q.empty())
    {
        node temp = q.top();
        q.pop();
        int u = temp.v;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = 0; i < Adj[u].size(); i++)
        {
            int v = Adj[u][i].v;
            int dis = Adj[u][i].dis;
            if(vis[v] == false)
            {
                if(dist[v] > dist[u] + dis)
                {
                    dist[v] = dist[u] + dis;
                    pre[v].clear();
                    pre[v].push_back(u);
                    q.push(node(v,dist[v]));
                }
                else if(dist[v] == dist[u] + dis)
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
int num = 0, maxpeople = 0;
void dfs(int s, int v)
{
    if(s == v)
    {
        num++;
        pathtemp.push_back(s);
        int people = 0;
        for(int i = 0; i < pathtemp.size(); i++)
        {
            people += weight[pathtemp[i]];
        }
        if(people > maxpeople)
        {
            maxpeople = people;
            path = pathtemp;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
        dfs(s, pre[v][i]);
    pathtemp.pop_back();
}
int main()
{
    cin >> n >> m >> c1 >> c2;
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &weight[i]);
    }
    int u, v, dis;
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &u, &v, &dis);
        Adj[u].push_back(node(v,dis));
        Adj[v].push_back(node(u,dis));
    }
    dijkstra(c1);
    dfs(c1, c2);
    printf("%d %d", num, maxpeople);
    return 0;
}

A1018

典型的找最短路径问题,只不过在处理path数组时需要一个结点一个结点的判断。

不能把最短路径求出后直接求总数量,因为可能会出现先要取一部分车,但是后面车太多又要带回去的情况。
需要在获得最短路径后在dfs里面对每个一个结点进行更新need和back,所以需要一个remain来记录当前有多少辆。

小技巧是在读入结点权值后可以让每个权值减去capacit/2,这样结点权值的正负就代表需要车还是留有车辆。

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int INF = 0x3fffffff;
struct node
{
    int v, dis;
    node(int _v, int _dis) : v(_v), dis(_dis){}
};
int c, n, m, idex;
vector<node> Adj[N];
int weight[N];
int dist[N], num[N];
bool inq[N];
vector<int> pre[N];
vector<int> pathtemp, path;
void spfa()
{
    fill(dist, dist + N, INF);
    memset(inq, false, sizeof(inq));
    queue<int> q;
    q.push(0);
    inq[0] = true;
    num[0]++;
    dist[0] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        inq[u] = false;
        for(int j = 0; j < Adj[u].size(); j++)
        {
            int v = Adj[u][j].v;
            int dis = Adj[u][j].dis;
            if(dist[v] > dist[u] + dis)
            {
                dist[v] = dist[u] + dis;
                pre[v].clear();
                pre[v].push_back(u);
                if(inq[v] == false)
                {
                    q.push(v);
                    inq[v] = true;
                    num[v]++;
                    if(num[v] >= n) return ;
                }
            }
            else if(dist[v] == dist[u] + dis)
            {
                pre[v].push_back(u);
            }
        }
    }
}

int minneed = INF, minback = INF;
void dfs(int v)
{
    if(v == 0)
    {
        int need = 0, back = INF, remain = 0;
        for(int i = pathtemp.size() - 1; i >= 0; i--)
        {
            if(remain >= abs(weight[pathtemp[i]]))
            {
                    remain += weight[pathtemp[i]];
            }
            else
            {
                if(weight[pathtemp[i]] < 0)
                {
                    need += ( abs(weight[pathtemp[i]]) - remain);
                    remain = 0;
                }
                else
                    remain += weight[pathtemp[i]];
            }
            back = remain;
        }
        if(minneed > need)
        {
            minneed = need;
            minback = back;
            path = pathtemp;
        }
        else if(minneed == need)
        {
            if(minback > back)
            {
                minback = back;
                path = pathtemp;
            }
        }
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
        dfs(pre[v][i]);
    pathtemp.pop_back();
}
int main()
{
    scanf("%d%d%d%d", &c, &n, &idex, &m);
    c /= 2;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &weight[i]);
        weight[i] -= c;
    }
    int u, v, d;
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &u, &v, &d);
        Adj[u].push_back(node(v, d));
        Adj[v].push_back(node(u, d));
    }
    spfa();
    dfs(idex);
    printf("%d 0->", minneed);
    for(int i = path.size() - 1; i >= 0; i--)
    {
        printf("%d", path[i]);
        if(i != 0) printf("->");
    }
    printf(" %d", minback);
    return 0;
}

dijkstra堆优化版本+dfs

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int c, n, m, sp;
int weight[N];
struct node
{
    int v, dis;
    node(int _v, int _dis):v(_v), dis(_dis){}
    friend bool operator<(const node& a, const node& b)
    {
        return a.dis > b.dis;
    }
};
vector<node> Adj[N];
vector<int> pre[N];
vector<int> path, pathtemp;
bool vis[N];
int dist[N];
void dijkstra(int st)
{
    fill(dist,dist+N, inf);
    memset(vis, false, sizeof(vis));
    dist[st] = 0;
    priority_queue<node> q;
    q.push(node(st, 0));
    while(!q.empty())
    {
        node temp = q.top();
        q.pop();
        int u = temp.v;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = 0; i < Adj[u].size(); i++)
        {
            int v = Adj[u][i].v;
            int dis = Adj[u][i].dis;
            if(vis[v] == false)
            {
                if(dist[v] > dist[u] + dis)
                {
                    dist[v] = dist[u] + dis;
                    pre[v].clear();
                    pre[v].push_back(u);
                    q.push(node(v,dist[v]));
                }
                else if(dist[v] == dist[u] + dis)
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
int minneed = inf, minback = inf;
void dfs(int s, int v)
{
    if(s == v)
    {
        pathtemp.push_back(v);
        int remain = 0, need = 0, back = 0;
        for(int i = pathtemp.size()-1; i>= 0; i--)
        {
            if(remain < abs(weight[pathtemp[i]]))
            {
                if(weight[pathtemp[i]] > 0)
                {
                    remain += weight[pathtemp[i]];
                }
                else
                {
                    need += (abs(weight[pathtemp[i]]) - remain);
                    remain = 0;
                }
            }
            else
            {
                remain += weight[pathtemp[i]];
            }
        }
        back = remain;
        if(need < minneed)
        {
            minneed = need;
            minback = back;
            path = pathtemp;
        }
        else if(need = minneed && back < minback)
        {
            minback = back;
            path = pathtemp;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
        dfs(s, pre[v][i]);
    pathtemp.pop_back();
}
int main()
{
    cin >> c >> n >> sp >> m;
    c /= 2;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &weight[i]);
        weight[i] -= c;
    }
    int u, v, dis;
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &u, &v, &dis);
        Adj[u].push_back(node(v,dis));
        Adj[v].push_back(node(u,dis));
    }
    dijkstra(0);
    dfs(0, sp);
    printf("%d ", minneed);
    for(int i = path.size() -1; i > 0; i--)
        printf("%d->", path[i]);
    printf("%d %d", path[0], minback);
    return 0;
}

A1030

SPFA算法

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3fffffff;
const int N = 510;
struct node
{
    int v, cost, dis;
    node(int _v, int _dis): v(_v), dis(_dis) {}
};
int cost[N][N];
vector<node> Adj[N];
int n, m, st, ed;
int dist[N];
bool inq[N];
int num[N];
set<int> pre[N];
vector<int> path, pathtemp;
void SPFA(int s)
{
    fill(dist, dist+N, INF);
    memset(num, 0, sizeof(num));
    memset(inq, false, sizeof(inq));
    queue<int> q;
    q.push(s);
    inq[s] = true;
    num[s]++;
    dist[s] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        inq[u] = false;
        for(int j = 0; j < Adj[u].size(); j++)
        {
            int v = Adj[u][j].v;
            int dis = Adj[u][j].dis;
            if(dist[v] > dist[u] + dis)
            {
                dist[v] = dist[u] + dis;
                pre[v].clear();
                pre[v].insert(u);
                if(inq[v] == false)
                {
                    q.push(v);
                    inq[v] = true;
                    num[v]++;
                    if(num[v] >= n) return;
                }
            }
            else if(dist[v] == dist[u] + dis)
            {
                pre[v].insert(u);
            }
        }
    }
}
int mincost = INF;
void dfs(int s, int v)
{
    if(s == v)
    {
        int c = 0;
        pathtemp.push_back(s);
        for(int i = pathtemp.size() - 1; i > 0; i--)
        {
            int id = pathtemp[i], idnext = pathtemp[i-1];
            c += cost[id][idnext];
        }
        if(c < mincost)
        {
            path = pathtemp;
            mincost = c;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(set<int>::iterator it = pre[v].begin(); it != pre[v].end(); it++)
        dfs(s,*it);
    pathtemp.pop_back();
}
int main()
{
    //fill(G[0], G[0] + N*N, INF);
    fill(cost[0], cost[0]+N*N, INF);
    scanf("%d%d%d%d", &n, &m, &st, &ed);
    int u, v, d, co;
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d%d", &u, &v, &d, &co);
        Adj[u].push_back(node(v, d));
        Adj[v].push_back(node(u, d));
        cost[u][v] = cost[v][u] = co;
    }
    SPFA(st);
    dfs(st, ed);
    for(int i = path.size() - 1; i >= 0; i--)
        cout << path[i] <<" ";
    printf("%d %d", dist[ed], mincost);
    return 0;
}

朴素dijkstra+dfs版本

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int n, m, s, d;
int G[N][N], cost[N][N];
int dist[N];
bool vis[N];
vector<int> pre[N];
vector<int> path, pathtemp;
void dijkstra(int s)
{
    fill(dist, dist + N, inf);
    memset(vis, false, sizeof(vis));
    dist[s] = 0;
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = inf;
        for(int j = 0; j < n; j++)
        {
            if(vis[j] == false && dist[j] < MIN)
            {
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(int v = 0; v < n; v++)
        {
            if(G[u][v] != inf && vis[v] == false)
            {
                if(dist[v] > dist[u] + G[u][v])
                {
                    dist[v] = dist[u] + G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if(dist[v] == dist[u] + G[u][v])
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
int mincost = inf;
void dfs(int s, int v)
{
    if(s == v)
    {
        pathtemp.push_back(v);
        int c = 0;
        for(int i = pathtemp.size() - 1; i > 0; i--)
        {
            int id = pathtemp[i-1], idnext = pathtemp[i];
            c += cost[id][idnext];
        }
        if(c < mincost)
        {
            mincost = c;
            path = pathtemp;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
    {
        dfs(s, pre[v][i]);
    }
    pathtemp.pop_back();
}
int main()
{
    fill(G[0], G[0]+N*N, inf);
    int u, v, dis, co;
    scanf("%d%d%d%d", &n, &m, &s, &d);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d%d", &u, &v, &dis, &co);
        if(G[u][v] > dis)
        {
            G[u][v] = G[v][u] = dis;
            cost[u][v] = cost[v][u] = co;
        }
    }
    dijkstra(s);
    dfs(s, d);
    for(int i = path.size() - 1; i >= 0; i--)
        printf("%d ", path[i]);
    printf("%d %d", dist[d], mincost);
    return 0;
}

A1072

本题也是dfs题目,只不过需要考虑的不是最短路径,而是先记录所有dist数组然后再dfs中计算最短平均距离和最大的最近距离。需要注意的是如何将字符串转换为数字。

几个坑点

1.输出的数据可能重复,比如同两个点有多个路径则选择最小的路,所以在输入时需要判定。
2.如果给定两个相同的点,所以需要先讲g[i][i]置为0
3.学会如何保留有效数字

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int inf = 0x3fffffff;
int n, m, s, d;
int G[N][N], cost[N][N];
int dist[N];
bool vis[N];
vector<int> pre[N];
vector<int> path, pathtemp;
void dijkstra(int s)
{
    fill(dist, dist + N, inf);
    memset(vis, false, sizeof(vis));
    dist[s] = 0;
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = inf;
        for(int j = 0; j < n; j++)
        {
            if(vis[j] == false && dist[j] < MIN)
            {
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(int v = 0; v < n; v++)
        {
            if(G[u][v] != inf && vis[v] == false)
            {
                if(dist[v] > dist[u] + G[u][v])
                {
                    dist[v] = dist[u] + G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if(dist[v] == dist[u] + G[u][v])
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
int mincost = inf;
void dfs(int s, int v)
{
    if(s == v)
    {
        pathtemp.push_back(v);
        int c = 0;
        for(int i = pathtemp.size() - 1; i > 0; i--)
        {
            int id = pathtemp[i-1], idnext = pathtemp[i];
            c += cost[id][idnext];
        }
        if(c < mincost)
        {
            mincost = c;
            path = pathtemp;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
    {
        dfs(s, pre[v][i]);
    }
    pathtemp.pop_back();
}
int main()
{
    fill(G[0], G[0]+N*N, inf);
    int u, v, dis, co;
    scanf("%d%d%d%d", &n, &m, &s, &d);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d%d%d", &u, &v, &dis, &co);
        if(G[u][v] > dis)
        {
            G[u][v] = G[v][u] = dis;
            cost[u][v] = cost[v][u] = co;
        }
    }
    dijkstra(s);
    dfs(s, d);
    for(int i = path.size() - 1; i >= 0; i--)
        printf("%d ", path[i]);
    printf("%d %d", dist[d], mincost);
    return 0;
}

A1087

前面几道题的结合,既要把字符串转换成数字,也要多重判断用dijkstra+dfs解决。

#include<bits/stdc++.h>
using namespace std;
const int N = 220;
const int inf = 0x3fffffff;
map<string, int> string2int;
map<int, string> int2string;
vector<int> pre[N];
vector<int> path, pathtemp;
int numperson = 1;
int weight[N];
int G[N][N];
int n, k;

int change(string str)
{
    if(string2int.find(str) != string2int.end())
        return string2int[str];
    else
    {
        string2int[str] = numperson;
        int2string[numperson] = str;
        return numperson++;
    }
}
bool vis[N];
int dist[N];
void dijkstra(int s)
{
    fill(dist, dist+N, inf);
    fill(vis, vis+N, false);
    dist[s] = 0;
    for(int i = 0; i < n; i++)
    {
        int u = -1, MIN = inf;
        for(int j = 0; j < n; j++)
        {
            if(vis[j] == false && dist[j] < MIN)
            {
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(int v = 0; v < n; v++)
        {
            if(vis[v] == false && G[u][v] != inf)
            {
                if(dist[v] > dist[u] + G[u][v])
                {
                    dist[v] = dist[u] + G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                }
                else if(dist[v] == dist[u] + G[u][v])
                {
                    pre[v].push_back(u);
                }
            }
        }
    }
}
int maxhap = 0, maxavg = 0, num = 0;;
void dfs(int s, int v)
{
    if(s == v)
    {
        num++;
        pathtemp.push_back(v);
        int hap = 0, avg = 0, len = pathtemp.size();
        for(int i = 0; i < len; i++)
        {
            hap += weight[pathtemp[i]];
        }
        avg = hap / (pathtemp.size() - 1);
        if(hap > maxhap)
        {
            maxhap = hap;
            maxavg = avg;
            path = pathtemp;
        }
        else if(hap == maxhap && avg > maxavg)
        {
            maxavg = avg;
            path = pathtemp;
        }
        pathtemp.pop_back();
        return ;
    }
    pathtemp.push_back(v);
    for(int i = 0; i < pre[v].size(); i++)
    {
        dfs(s,pre[v][i]);
    }
    pathtemp.pop_back();
}
int main()
{
    fill(G[0], G[0] +N*N, inf);
    string2int["ROM"] = 0;
    int2string[0] = "ROM";
    string c1, c2;
    cin >> n >> k >> c1;
    int st = change(c1);
    int id, w;
    for(int i = 0; i < n - 1; i++)
    {
        cin >> c1 >> w;
        id = change(c1);
        weight[id] += w;
    }
    int u, v, dis;
    for(int i = 0; i < k; i++)
    {
        cin >> c1 >> c2 >> dis;
        u = change(c1);
        v = change(c2);
        G[u][v] = G[v][u] = dis;
    }
    dijkstra(st);
    dfs(st, 0);
    printf("%d %d %d %d\n", num, dist[0], maxhap, maxavg);
    for(int i = path.size() - 1; i >= 0; i--)
    {
        cout << int2string[path[i]];
        if(i != 0) printf("->");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值