算法第9章 图算法设计

7-1 旅游规划

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 510;
int g[N][N];
int n,m,s,d;
int dist[N];
int w[N],t[N][N];
bool st[N];
void dijkstra(){
memset(dist, 0x3f, sizeof dist);
dist[s] = 0;
for(int i=0;i<n;i++){
    int k = -1;
    for(int j = 0;j<n;j++)
        if(!st[j] && (k == -1 || dist[k] > dist[j]))
            k = j;
    st[k] = true;
    for(int j=0;j<n;j++){
        if(!st[j] && dist[j] > dist[k] + g[k][j]){
            dist[j] = dist[k] + g[k][j];
            w[j] = w[k] + t[k][j];//随时更新金额
        }
        else if(!st[j] && dist[j] == dist[k] + g[k][j] && w[j] > w[k] + t[k][j])
            w[j] = w[k] + t[k][j];
    } 
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&s,&d);
memset(g, 0x3f, sizeof g);
memset(t, 0x3f, sizeof t);
for(int i=1;i<=m;i++){
    int a,b,c,f;
    scanf("%d%d%d%d",&a,&b,&c,&f);
    g[a][b] = c;
    g[b][a] = c;
    t[a][b] = f;
    t[b][a] = f;
}
//for(int i=0;i<n;i++) w[i] = t[s][i];
dijkstra();
printf("%d %d\n",dist[d],w[d]);
return 0;
}


7-2 大众情人

#include<iostream>
#include<vector>
using namespace std;
const int N = 510;
int g[N][N],sex[N],d[N];
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        if(i==j) g[i][j]=0;
        else g[i][j]=1e9;

for(int i=1;i<=n;i++)
{
    char op;int k;scanf(" %c %d",&op,&k);
    if(op=='F') sex[i]=1;//女生 
    else sex[i]=2;//男生 
    for(int j=1;j<=k;j++)
    {
        int a,b;scanf("%d:%d",&a,&b);
        g[i][a]=b;
    } 
}
for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        if(sex[i]!=sex[j])
            d[i]=max(d[i],g[j][i]);

int d1=1e9,d2=1e9;//d1,表示男对女的距离   d2,表示女对男的距离 
for(int i=1;i<=n;i++)
{
    if(sex[i]==2) d1=min(d1,d[i]);//找男对女的最小距离 ,即男性的"大众情人" 
    else d2=min(d2,d[i]);//找女对男的最小距离 ,即女性的 "大众情人" 
}

vector<int> a,b;
for(int i=1;i<=n;i++)//女性的"大众情人" 
{
    if(sex[i]==2) continue;
    if(d[i]==d2) a.push_back(i);
}	

for(int i=1;i<=n;i++)//男性的"大众情人" 
{
    if(sex[i]==1) continue;
    if(d[i]==d1) b.push_back(i);
}
 
printf("%d",a[0]); 
for(int i=1;i<(int)a.size();i++) 
    printf(" %d",a[i]);	
    
puts("");

printf("%d",b[0]); 
for(int i=1;i<(int)b.size();i++)
    printf(" %d",b[i]);

return 0;
}

7-3 寻宝图

#include <iostream>
using namespace std;
const int MAXN=100005;
string a[MAXN];
//这里不定义二维数组以防止数组过大
int n,m;
int flag=0;
int px[]={1,0,-1,0},py[]={0,1,0,-1};
//格子控制左上右下移动
//dfs递归
void dfs(int i,int j)
{
if(i<0||i>=n||j<0||j>=m||a[i][j]=='0')return;
//该点不是1,或者i,j超出边界
if(a[i][j]>'1')flag=1;//是宝藏
a[i][j]='0';
//置该点为0
for(int k=0;k<4;k++)dfs(i+px[k],j+py[k]);
//向各个方向延申
}
int main()
{
int c=0,cnt=0;
cin>>n>>m;
for(int i=0;i<n;i++)
{
    cin>>a[i];
}
for(int i=0;i<n;i++){
    for(int j=0;j<m;j++){
        if(a[i][j]>'0'){
            c=c+1;
            flag=0;
            dfs(i,j);
            if(flag)cnt++;
        }
    }
}
cout<<c<<" "<<cnt<<endl;
}

7-4 最小生成树-Prim算法(从任意顶点开始)

#include<bits/stdc++.h>
using namespace std;
int inf=0x3f3f3f3f;
int graph[10000][10000]={0};
int lowcost[10000]={0};//点集
int tree[10000]={0};
int m,n,ls;
void prim(int s)
{
    for(int i=1;i<=n;i++)
    {
        if(i==s)
            lowcost[i]=0;
        else
        lowcost[i]=graph[s][i];
        tree[i]=s;//初始化,所有的边都待选
    }
    int minn,pos;
    for(int i=1;i<n;i++)//循环了n-1次,因为n个点,n-1个边
    {
        minn=inf;
        for(int j=1;j<=n;j++)
        {
            if(lowcost[j]!=0&&lowcost[j]<minn)
            {
                minn=lowcost[j];
                pos=j;
            }//这个找的就是点集周围的最小边
        }
        cout<<(tree[pos]<pos?tree[pos]:pos)<<","<<(tree[pos]>pos?tree[pos]:pos)<<","<<graph[tree[pos]][pos]<<endl;//每找到一个边就输出一个边
        if(minn==inf)
            break;
        lowcost[pos]=0;//加入!!
        for(int j=1;j<=n;j++)
        {
            if(lowcost[j]!=0&&graph[pos][j]<lowcost[j])//因为没在点集里,s到j比较大,pos到j小,就更新一下
            {
                lowcost[j]=graph[pos][j];//其实就是点集到j最短的距离
                tree[j]=pos;//加入到tree的待选,下次循环会选出来合适的,到时候这里的j会是合适的pos,这里的pos对应上一次合适的值。
            }
        }
    }
}
int main()
{
    cin>>n>>m>>ls;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            graph[i][j]=inf;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        cin>>graph[a][b];
        graph[b][a]=graph[a][b];
    }
    prim(ls);
}

7-5 h0359. 并查集

#include <iostream>
#include <vector>

using namespace std;

vector<int> parent;

int find(int x) {
    if (parent[x] == x) {
        return x;
    } else {
        return parent[x] = find(parent[x]);
    }
}

void merge(int a, int b) {
    int rootA = find(a);
    int rootB = find(b);
    if (rootA != rootB) {
        parent[rootB] = rootA;
    }
}

int main() {
    int n, m;
    cin >> n >> m;

    // 初始化并查集
    parent.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
        parent[i] = i;
    }

    char op;
    int a, b;
    for (int i = 0; i < m; ++i) {
        cin >> op >> a >> b;
        if (op == 'M') {
            merge(a, b);
        } else if (op == 'Q') {
            if (find(a) == find(b)) {
                cout << "Yes" << endl;
            } else {
                cout << "No" << endl;
            }
        }
    }

    return 0;
}

7-6 h0360. 并查集2

#include <iostream>

using namespace std;

const int N = 100010;
int n, m;
int p[N], cnt[N];

int find(int x) {
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++ ) p[i] = i, cnt[i] = 1;
    
    while(m -- ) {
        char op[3];
        int a, b;
        scanf("%s", op);
        if(op[0] == 'C') {
            scanf("%d%d", &a, &b);
            if(find(a) == find(b)) continue;
            cnt[find(b)] += cnt[find(a)];
            p[find(a)] = find(b);
        } else if(op[1] == '1') {
            scanf("%d%d", &a, &b);
            if(find(a) == find(b)) printf("Yes\n");
            else printf("No\n");
        } else {
            scanf("%d", &a);
            printf("%d\n", cnt[find(a)]);
        }
    }
    
    return 0;
    
}

7-7 h0361. 并查集3

#include<iostream>
#include<cstdio>
 
using namespace std;
int pre[50003],rel[50003];
 
int f(int x){
    if(x==pre[x])return x;
    int tmp=pre[x];
    pre[x]=f(pre[x]);
    rel[x]=(rel[x]+rel[tmp])%3;
    return pre[x];
}
 
int link(int x,int y,int flag){
    int root1=f(x),root2=f(y);
    if(root1==root2){//表示已经合并啦
        if(flag!=(3-rel[x]+rel[y])%3)return 0;
        else return 1;
    }
    pre[root2]=root1;
    rel[root2]=(rel[x]+flag+3-rel[y])%3;
    return 1;
}
 
int main(){
    int n,k,flag,x,y;
    scanf("%d%d",&n,&k);
    int ans=0;
    for(int i=1;i<=n;i++){
        pre[i]=i;
        rel[i]=0;
    }
    while(k--){
        scanf("%d%d%d",&flag,&x,&y);
        if(x>n||y>n){ans++;continue;}
        if(flag==2&&x==y){ans++;continue;}
        if(!link(x,y,flag-1))ans++;
    }
    printf("%d\n",ans);
}

7-8 吉利矩阵

#include<iostream>
using namespace std;
const int N=20;
int a[N][N];
int main(){
int l,n;cin>>l>>n;
a[2][2]=3;
a[2][3]=21;
a[2][4]=282;
a[3][2]=4;
a[3][3]=55;
a[3][4]=2008;
a[4][2]=5;
a[4][3]=120;
a[4][4]=10147;
a[5][2]=6;
a[5][3]=231;
a[5][4]=40176;
a[6][2]=7;
a[6][3]=406;
a[6][4]=132724;
a[7][2]=8;
a[7][3]=666;
a[7][4]=381424;
a[8][2]=9;
a[8][3]=1035;
a[8][4]=981541;
a[9][2]=10;
a[9][3]=1540;
a[9][4]=2309384;
cout<<a[l][n];
}

7-9 最小费用流

#include <iostream>
#include <vector>
#include <queue>
#include <limits>

using namespace std;

const int INF = numeric_limits<int>::max();

struct Edge {
    int to, cap, cost, rev;
};

vector<vector<Edge>> graph;
vector<int> dist;
vector<int> prevv, preve;

void add_edge(int from, int to, int cap, int cost) {
    graph[from].push_back(Edge{to, cap, cost, static_cast<int>(graph[to].size())});
    graph[to].push_back(Edge{from, 0, -cost, static_cast<int>(graph[from].size()) - 1});
}

pair<int, int> min_cost_flow(int s, int t) {
    int flow = 0, cost = 0;
    while (true) {
        queue<int> que;
        dist.assign(graph.size(), INF);
        dist[s] = 0;
        que.push(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (int i = 0; i < graph[v].size(); ++i) {
                Edge &e = graph[v][i];
                if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
                    dist[e.to] = dist[v] + e.cost;
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    que.push(e.to);
                }
            }
        }
        if (dist[t] == INF) {
            break;
        }
        int d = INF;
        for (int v = t; v != s; v = prevv[v]) {
            d = min(d, graph[prevv[v]][preve[v]].cap);
        }
        flow += d;
        cost += d * dist[t];
        for (int v = t; v != s; v = prevv[v]) {
            Edge &e = graph[prevv[v]][preve[v]];
            e.cap -= d;
            graph[v][e.rev].cap += d;
        }
    }
    return make_pair(flow, cost);
}

int main() {
    int n, m;
    cin >> n >> m;

    graph.resize(n + 1);
    dist.resize(n + 1);
    prevv.resize(n + 1);
    preve.resize(n + 1);

    for (int i = 0; i < m; ++i) {
        int s, t, c, w;
        cin >> s >> t >> c >> w;
        add_edge(s, t, c, w);
    }

    pair<int, int> result = min_cost_flow(1, n);
    cout << result.first << " " << result.second << endl;

    return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暴躁的梁小忠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值