最小总代价(洛谷-U17433)

题目描述

n个人在做传递物品的游戏,编号为1-n。

游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。

即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;

求当物品经过所有n个人后,整个过程的总代价是多少。

输入输出格式

输入格式:

第一行为n,表示共有n个人(16>=n>=2);

以下为n*n的矩阵,第i+1行、第j列表示物品从编号为i的人传递到编号为j的人所花费的代价,特别的有第i+1行、第i列为-1(因为物品不能自己传给自己),其他数据均为正整数(<=10000)。

输出格式:

一个数,为最小的代价总和。

输入输出样例

输入样例#1:

2
-1 9794
2724 –1

输出样例#1:

2724

思路:状压 DP 入门题

每个人只能被传递一次,用一个 n 位二进制数来表示每个人是否被访问过,但这无法知道物品在谁手中,因此加一个状态,来表示物品在谁手中。

用 f[i][j] 表示在 i 状态时最后的一个是 j,初始状态为 f[1<<i][i]=0;表示一开始物品在i手中,所求状态为 min(f[(1<<n)-1][j]);  因此有转移方程:f[i][j]=min(f[i-(1<<j)][k]+cost[k][j],f[i][j]) 

k 表示从 k 点转移到了 j 位置,所以要求 j、k 都应该是集合 i 中的元素

源代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 1001
#define MOD 10007
#define E 1e-6
#define LL long long
using namespace std;
LL f[1<<17][20],cost[20][20];
int main()
{
    int n;
    cin>>n;

    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>cost[i][j];

    /*标识状态初始化*/
    memset(f,127,sizeof(f));
    for(int i=0;i<n;i++)
        f[1<<i][i]=0;

    int cnt=(1<<n)-1;
    for(int i=1;i<=cnt;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i&(1<<j))
            {
                for(int k=0;k<n;k++)
                {
                    if( j!=k && (i&(1<<k)) )//k在状态i中不存在
                    {
                        LL x=(i-(1<<j));
                        f[i][j]=min(f[x][k]+cost[k][j],f[i][j]);
                    }
                }
            }
        }
    }

    LL minn=INF;
    for(int i=0;i<n;i++)
        minn=min(minn,f[cnt][i]);
    cout<<minn<<endl;

    return 0;
}

 

### 使用Dijkstra算法实现单源最短路径 对于单源最短路径问题,在C语言中可以采用经典的Dijkstra算法来解决。此方法适用于带权图中的最短路径计算,其中权重代表边的成本。 下面是一个基于邻接矩阵表示法的简单版本: ```c #include <stdio.h> #include <limits.h> #define V 9 // 节点数量 // 找到距离最小且未处理过的顶点 int minDistance(int dist[], int sptSet[]) { int min = INT_MAX, min_index; for (int v = 0; v < V; v++) if (!sptSet[v] && dist[v] <= min) min = dist[v], min_index = v; return min_index; } void printSolution(int dist[], int n) { printf("Vertex Distance from Source\n"); for (int i = 0; i < V; i++) printf("%d \t\t %d\n", i, dist[i]); } void dijkstra(int graph[V][V], int src) { int dist[V]; // 存储最终结果的距离数组 int sptSet[V]; // 记录哪些节点已经被加入到了SPT(Shortest Path Tree) for (int i = 0; i < V; i++) dist[i] = INT_MAX, sptSet[i] = 0; dist[src] = 0; for (int count = 0; count < V - 1; count++) { int u = minDistance(dist, sptSet); sptSet[u] = 1; for (int v = 0; v < V; v++) if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) dist[v] = dist[u] + graph[u][v]; } printSolution(dist, V); } ``` 上述代码实现了基本形式下的Dijkstra算法[^2]。需要注意的是这段程序假设输入图为连通无向加权图,并通过二维数组`graph[][]`定义了各结点间的连接关系以及对应的代价;而实际应用时可能还需要考虑更多细节比如异常情况处理等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值