百炼OJ, 题目链接
思路,典型的bfs问题,但需要处理的条件较多,此种题适合使用结构体来做,注意熟练使用结构体编程。
先贴上代码,以后再多写几遍,这里用到了状态压缩的方法记录宝石的数量。
#include
#include
#include
#include
using namespace std;
#define MAX 201
char a[MAX][MAX];
struct Node
{
int x, y; //坐标。
int num = 0; //存储宝石数目。
int deep = 0; //搜索深度。
Node() {
}
Node(int xx, int yy, int gg, int dd) : x(xx), y(yy), num(gg), deep(dd) {
}
};
int dir[4][2] = {{0, -1},{-1, 0},{0, 1},{1, 0}};
int visited[MAX][MAX][1 << 5 - 1]; //宝石数目最大11111
int r, c, k, doorCount;
Node doors[11];
int bit1Count(int value) {
unsigned int count = 0;
while (value > 0) { // until all bits are zero
if ((value & 1) == 1) // check lower bit
count++;
value >>= 1; // shift bits, removing lower bit
}
return count;
}
void printQueue(std::queue<Node> q) {
while (!q.empty()) {
Node node = q.front();
q.pop();
cout << "(" << node.x << ", " << node.y << ", "
<< bit1Count(node.num) << ", " << node.deep << ") ";
}
cout << endl << endl;
}
int getTarget(Node* node, Node* endNode) {
return (node->x == endNode->x && node->y == endNode->y && bit1Count(node->num) >= k);
}
int bfs(Node* startNode, Node* endNode) {
if (startNode == NULL || endNode == NULL) return -1;
memset(visited, 0, sizeof(visited));
visited[startNode->x][startNode->y][0] = 1; //置起点已经访问
queue<Node> q;
q.push(*startNode); //起点入队
while (!q.empty()) {
Node node = q.front(); //取队首元素,出队
q.pop();
for (int i = 0; i < 4; i++) { // 遍历四个方向
int newX = node.x + dir[i][0];
int newY = node.y + dir[i][1];
if (newX < 0 || newX >= r || newY < 0 || newY >= c) continue; // 越界则下一个
if (a[newX][newY] == '#' || visited[newX][newY][node.num]==1) continue; //碰到墙或者已经访问过,则下一个
//不是墙壁并且此节点没访问过
visited[newX][newY][node.num] = 1;
// 当前路可走
Node newNode(newX, newY, node.num, node.deep + 1);
if (a[newX][newY] >= '0' && a[newX][newY] <= '4') { // 遇到宝石
newNode.num |= 1 << (a[newX][newY] - '0'); //状态压缩记录宝石数量
}
if ((newNode.x == endNode->x && newNode.y == endNode->y && bit1Count(newNode.num) >= k)) {
return newNode.deep;
}
// 没有达到终点,则当前点入队
q.push(newNode);
//如果是传送门的话就将所有其它传送门也加入搜索队列。
if (a[newX][newY] == '$') {
for (int j = 0; j < doorCount; j++) {
Node currNode = doors[j];
if (currNode.x == newX && currNode.y == newY) continue;
Node doorNode(currNode.x, currNode.y, newNode.num, newNode.deep);
q.push(doorNode);
}
}
}
}
return -1;
}
int main() {
int t;
cin >> t; //t组数据
while (t--) {
// Node记录坐标,宝石数目,深度
Node *startNode = NULL, *endNode = NULL;
cin >> r >> c >> k; //r*c矩阵,k个宝石
doorCount = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cin >> a[i][j];
switch (a[i][j]) {
case '$': //记录所有传送门的位置。
doors[doorCount++] = Node(i, j, 0, 0);
break;
case 'S': // 记录起点位置
startNode = new Node(i, j, 0, 0);
break;
case 'E': // 记录终点位置
endNode = new Node(i, j, 0, 0);
}
}
}
int ans=bfs(startNode, endNode);
ans == -1 ? (cout << "oop!" << endl) : (cout << ans << endl);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
//16.57
struct Node{
int x,y; // 坐标
int num; // 宝石个数
int depth; // 深度
Node(){
}
Node(int xx,int yy,int nn,int dd) :x(xx),y(yy),num(nn),depth(dd) {}
};
int R,C,K,ct=0;
//vector> a(R,vector(C));
char a[200][200];
int dx[]={-1,1,0,0}; //上下左右
int dy[]={0,0,-1,1};
Node jewelNode[11];
int visited[200][200][1 << 5 - 1]; //宝石数目最大11111
int bit1Count(int value) {
unsigned int count = 0;
while (value > 0) { // until all bits are zero
if ((value & 1) == 1) // check lower bit
count++;
value >>= 1; // shift bits, removing lower bit
}
return count;
}
int bfs(Node *startNode,Node *endNode){
// 把startNode加入队列
visited[startNode->x][startNode->y][0] = 1; //置起点已经访问
queue<Node> q; // queue q行不行?
q.push(*startNode); //起点入队 q.push(startNode)?
while(!q.empty()){
Node node=q.front();q.pop(); // 取队首元素,出队
// 对四个方向遍历
for(int i=0;i<4;i++){
int newx=node.x+dx[i];
int newy=node.y+dy[i];
// 越界或者已经访问则跳过--------------visited数组为什么是三维的: 包含了宝石的情况
if(newx<0||newx>=R||newy<0||newy>=C||visited[newx][newy][node.num]==1) continue;
// 碰到#则走不通
if(a[newx][newy]=='#') continue;
// 其余情况均可走,标记为已经访问
visited[newx][newy][node.num]=1;
Node tempNode(newx, newy, node.num, node.depth+1); // 存下当前结果
// 碰到宝石
if(a[newx][newy]>='0'&&a[newx][newy]<='4'){
tempNode.num |= 1 << (a[newx][newy]-'0');
}
// 终止条件
if(newx==endNode->x&&newy==endNode->y&&bit1Count(tempNode.num)>=K) return tempNode.depth;
q.push(tempNode);
if(a[newx][newy]=='&'){ // 把所有传送门加入队列
for(int j=0;j<ct;j++){
if(jewelNode[j].x==newx&&jewelNode[j].y==newy) continue;
Node tNode(jewelNode[j].x, jewelNode[j].y, tempNode.num, tempNode.depth);
q.push(tNode);
}
}
// 如果遇到传送门
}
}
return -1;
}
int main()
{
int T=0;
cin>>T;
while(T--){
cin>>R>>C>>K; // R*C矩阵,K种类型宝石
// 读取字符矩阵
Node *startNode=NULL,*endNode=NULL;
for(int i=0;i<R;i++){
for(int j=0;j<C;j++){
cin>>a[i][j];
switch(a[i][j]){
case 'S': startNode=new Node(i,j,0,0);break; // 记录起点
case 'E': endNode=new Node(i,j,0,0);break; // 记录终点
case '$': jewelNode[ct++]=Node(i,j,0,0); // 记录宝石数量和位置
// 数组为什么就不可以 new Node(i,j,0,0)
}
}
}
int ans=bfs(startNode,endNode);
cout<<ans;
// ans == -1 ? (cout << "oop!" << endl) : (cout << ans << endl);
}
}
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
int vis[100][100];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int m,n; //m行n列
char map[100][100];
// 定义结构体
typedef struct node{
int x,y;
int step;
node() {
}
node(int xx, int yy, int sp) : x(xx), y(yy), step(sp){
}
}Node;
int bfs(Node* startNode,Node* endNode){
if (startNode == NULL || endNode == NULL) return -1;
// 把起点加入队列
queue<Node*> q;
q.push(startNode);
vis[startNode->x][startNode->y]=1;
while(!q.empty()){
Node* temp=q.front();
q.pop();
int newx,newy;
for(int i=0;i<4;i++){
newx=temp->x+dir[i][0];
newy=temp->y+dir[i][1];
if(newx>=0&&newx<m&&newy>=0&&newy<n){
if(vis[newx][newy]==0&&map[newx][newy]!='#'){ // 未访问过
Node* newNode=new Node(newx, newy,temp->step + 1);
vis[newx][newy]=1;
if(newx==endNode->x&&newy==endNode->y)
return newNode->step;
q.push(newNode);
// cout<x<<" "<y<
}
}
}
}
return -1;
}
int main(){
// 读取字符矩阵
while(scanf("%d%d",&m,&n)!=EOF&&(m||n)) {
Node* startNode=NULL;
Node* endNode=NULL;
string s="";
// 初始化地图并记录地图起点和终点
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>map[i][j];
if(map[i][j]=='@') startNode=new Node(i,j,0);
else if(map[i][j]=='*') endNode=new Node(i,j,0);
}
}
int ans=bfs(startNode, endNode);
cout << ans << endl;
}
}
题目链接
算法思路
指定一个节点,例如我们要计算 ‘A’ 到其他节点的最短路径
引入两个集合(S、U),S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点(以及A到该点的路径,注意 如上图所示,A->C由于没有直接相连 初始时为∞)
初始化两个集合,S集合初始时 只有当前要计算的节点,A->A = 0,
U集合初始时为 A->B = 4, A->C = ∞, A->D = 2, A->E = ∞
从U集合中找出路径最短的点,加入S集合,例如 A->D = 2
更新U集合路径,if ( ‘D 到 B,C,E 的距离’ + ‘AD 距离’ < ‘A 到 B,C,E 的距离’ ) 则更新U
循环执行 4、5 两步骤,直至遍历结束,得到A 到其他节点的最短路径
链接:https://www.jianshu.com/p/ff6db00ad866
算法模板:
输入用例:
5 7
1 2 4
1 4 2
2 4 1
2 3 4
3 4 1
3 5 3
4 5 7
输出用例:
6
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
int main(){
// 输入n结点,m条路径
int adjMatrix[110][110],dist[110],vis[110];
int n,m;
cin>>n>>m;
// 题目要求找到1号点到n号点的最短距离
// 输入起点,终点,距离
int a,b,c;
// 初始化邻接矩阵
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) adjMatrix[i][j]=0;
else adjMatrix[i][j]=inf;
}
}
// 读取输入给邻接矩阵赋值
for(int i=1;i<=m;i++){
cin>>a>>b>>c;
adjMatrix[a][b]=adjMatrix[b][a]=c;
}
// 初始化dist矩阵
for(int i=1;i<=n;i++){
dist[i]=inf;
}
for(int i=1;i<=n;i++){
if(dist[i]>adjMatrix[1][i])
dist[i]=adjMatrix[1][i];
}
vis[1]=1;
//
for(int i=1;i<=n;i++){
int mindis=inf,j=1;
for(int i=1;i<=n;i++){ // 找到剩下的所有点中离起点最近的点,置已访问
if(vis[i]==0&&mindis>dist[i]){
mindis=dist[i];
j=i;
}
}
vis[j]=1;
// 更新dist矩阵
for(int i=1;i<=n;i++){
if(dist[i]>adjMatrix[j][i]+dist[j])
dist[i]=adjMatrix[j][i]+dist[j];
}
}
cout<<dist[n];
return 0;
}
本题代码如下:
#include
#include
#include
using namespace std;
#define inf 0xfffffff
int map[110][110],dis[110],visit[110];
int n,m;
int dijstra()
{
memset(visit,0,sizeof(visit));
for (int i=1;i<=n;i++)
{
dis[i]=map[1][i]; // dis数组存下起点到其他点的距离
}
visit[1]=1;
dis[1]=0;
for (int i=1;i<=n;i++) // 对n个点遍历
{
int pos;
int min=inf;
for (int j=1;j<=n;j++)
{
if (visit[j]==0&&min>dis[j]) // 找到最小的dis
{
pos=j;
min=dis[j];
} /// 找出U集合中路径最短的节点D 加入S集合
}
visit[pos]=1; // 置为已访问
for (int j=1;j<=n;j++)
{
// 遍历,找出起点到j+j到终点的最短路径
if (!visit[j]&&dis[j]>dis[pos]+map[pos][j])
{
dis[j]=dis[pos]+map[pos][j]; // 更新dis
}
}
}
return dis[n];
}
int main()
{
int i,j;
while(~scanf("%d%d",&n,&m),n||m) // 输入节点数量和道路数量
{
for(i=1;i<=n;++i)
{
for(j=1;j<=n;++j)
{
map[i][j]=inf;
}
}
int a,b,c;
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&a,&b,&c); // 起点,终点,权值
if(c<map[a][b])
map[a][b]=map[b][a]=c; // 更新map
}
int count=dijstra();
printf("%d\n",count);
}
return 0;
}
例题:
测试输入的第1行给出评估的道路条数N,村庄数目M;随后的 N 行,每行给出三个正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。
输入示例:
9 14
1 2 4
2 3 8
3 4 7
4 5 9
5 6 10
6 7 2
7 8 1
8 9 7
2 8 11
3 9 2
7 9 6
3 6 4
4 6 14
1 8 8
输出示例:
37
kruskal算法:
加边法,以下图A为起点,手动模拟结果如下所示:
Kruskal算法的高效实现需要一种称作并查集的结构。
Kruskal算法的过程:
代码模板:
#include
#include
#include
#define MAXN 11 //顶点个数的最大值
#define MAXM 20 //边的个数的最大值
using namespace std;
struct edge //边
{
int u, v, w; //边的顶点、权值
}edges[MAXM]; //边的数组
int parent[MAXN]; //parent[i]为顶点 i 所在集合对应的树中的根结点
int n, m; //顶点个数、边的个数
int i, j; //循环变量
void UFset( ) //初始化
{
for( i=1; i<=n; i++ )
parent[i] = -1;
}
int Find( int x ) //查找并返回节点 x 所属集合的根结点
{
int s; //查找位置
for( s=x; parent[s]>=0; s=parent[s] );
while( s!=x ) //优化方案―压缩路径,使后续的查找操作加速。
{
int tmp = parent[x];
parent[x] = s;
x = tmp;
}
return s;
}
//将两个不同集合的元素进行合并,使两个集合中任两个元素都连通
void Union( int R1, int R2 )
{
int r1 = Find(R1), r2 = Find(R2); //r1 为 R1 的根结点,r2 为 R2 的根结点
int tmp = parent[r1] + parent[r2]; //两个集合结点个数之和(负数)
//如果 R2 所在树结点个数 > R1 所在树结点个数(注意 parent[r1]是负数)
if( parent[r1] > parent[r2] ) //优化方案――加权法则
{
parent[r1] = r2;
parent[r2] = tmp;
}
else
{
parent[r2] = r1;
parent[r1] = tmp;
}
}
bool cmp( edge a, edge b ) //实现从小到大排序的比较函数
{
return a.w <= b.w;
}
void Kruskal( )
{
int sumweight = 0; //生成树的权值
int num = 0; //已选用的边的数目
int u, v; //选用边的两个顶点
UFset( ); //初始化 parent[]数组
for( i=0; i<m; i++ )
{
u = edges[i].u; v = edges[i].v;
if( Find(u) != Find(v) ) //u和v不是一个掌门,即不连通
{
printf( "%d %d %d\n", u, v, edges[i].w );
sumweight += edges[i].w;
num++;
Union(u,v); // 合并
}
if( num>=n-1 ) break; // 取到n-1个边即结束
}
printf( "weight of MST is %d\n", sumweight );
}
int main( )
{
int u, v, w; //边的起点和终点及权值
scanf( "%d%d", &n, &m ); //顶点数 n,边数m
for( int i=0; i<m; i++ )
{
scanf( "%d%d%d", &u, &v, &w ); //读入边的起点和终点,以及权值
edges[i].u = u; edges[i].v = v; edges[i].w = w;
}
sort(edges,edges+m,cmp);
Kruskal();
return 0;
}
此题的难点在于
- 模拟棋的行走------------------------------使用空格位置做每次的起点
- 模拟黑白轮流执棋-----------------------需要记录上一次执棋的颜色
- 有黑白先后手之分------------------------分类深搜取最短的。
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
char a[5][5];
int ans,Ox1=0,Oy1,Ox2,Oy2,dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
bool check() //检查当前棋盘是否构成四子连棋
{
// 4*4的棋盘,只有行、列、双斜线四种方式
for(int i=1;i<=4;i++)
{
if (a[i][1]==a[i][2]&&a[i][1]==a[i][3]&&a[i][1]==a[i][4]) return 1;
if (a[1][i]==a[2][i]&&a[1][i]==a[3][i]&&a[1][i]==a[4][i]) return 1;
}
if (a[1][1]==a[2][2]&&a[1][1]==a[3][3]&&a[1][1]==a[4][4]) return 1;
if (a[1][4]==a[2][3]&&a[1][4]==a[3][2]&&a[1][4]==a[4][1]) return 1;
return 0;
}
bool can(int x,int y,char p)
{
return x>=1&&x<=4&&y>=1&&y<=4&&a[x][y]!=p;
}
bool dfs(int x1,int y1,int x2,int y2,char pre,int step) //pre表示先手颜色
{
// dfs(Ox1,Oy1,Ox2,Oy2,'W',0)
if (step==ans) //搜索深度达到上限,停止
{
if (check()) return 1;
else return 0;
}
// 对四个方向遍历
for(int i=0;i<4;i++)
{
int nx1,ny1,nx2,ny2;
nx1=x1+dir[i][0];
ny1=y1+dir[i][1];
nx2=x2+dir[i][0];
ny2=y2+dir[i][1];
// 如果当前坐标为有效位置
if (can(nx1,ny1,pre))
{
swap(a[x1][y1],a[nx1][ny1]); //交换
if (dfs(nx1,ny1,x2,y2,(pre=='B'?'W':'B'),step+1)) return 1; // 轮流
swap(a[x1][y1],a[nx1][ny1]);
}
if (can(nx2,ny2,pre))
{
swap(a[x2][y2],a[nx2][ny2]);
if (dfs(x1,y1,nx2,ny2,(pre=='B'?'W':'B'),step+1)) return 1;
swap(a[x2][y2],a[nx2][ny2]);
}
}
return 0;
}
int main()
{
// 读取棋盘
for(int i=1;i<=4;i++)
{
char s[5];
scanf("%s",s);
for(int j=1;j<=4;j++)
{
a[i][j]=s[j-1];
// 分别记录下O的位置
if (a[i][j]=='O')
{
if (Ox1==0)
Ox1=i,Oy1=j;
else
Ox2=i,Oy2=j;
}
}
}
for(ans=1;ans<=inf;ans++) //ans枚举深度上限
{
if (dfs(Ox1,Oy1,Ox2,Oy2,'W',0)) break; //黑先手
if (dfs(Ox1,Oy1,Ox2,Oy2,'B',0)) break; //白先手
}
printf("%d",ans);
return 0;
}
思路:典型的dp,先置马的控制点为1,令其他点均为0,0代表当前路可走,此处在处理的时候不需要判断边界条件,主要此处的巧妙使用。
//刷表法
#include
using namespace std;
int n, m, x, y, a[20][20], dp[20][20];
int main(){
cin>>n>>m>>x>>y; //行,列,马的坐标
a[x][y] = 1;
a[x-1][y-2] = a[x-1][y+2] = a[x+1][y-2] = a[x+1][y+2] = 1; // 躺 "日"
a[x-2][y-1] = a[x-2][y+1] = a[x+2][y-1] = a[x+2][y+1] = 1; //正 "日"
dp[0][0] = 1; //初始值, 刷表时不会覆盖所以可以直接放
for(int i = 0; i <= n; i++){
for(int j = 0; j <= m; j++){
// 0位安全点,可走
if(a[i+1][j]==0) // 右移安全,则右移点到达次数+当前
dp[i+1][j] += dp[i][j];
if(a[i][j+1]==0)
dp[i][j+1] += dp[i][j];
}
}
cout<<dp[n][m]<<"\n";
return 0;
}
#include
#include
using namespace std;
int dp[20005]={0};
int main()
{
int n,v;
cin>>v>>n; //输入体积和物品数
int volume;
for(int i=1;i<=n;i++)
{
cin>>volume; // 物品体积
for(int j=v;j>=volume;j--) //j为当前箱子的剩余体积,要比物体体积大才操作
{
//dp[j]为箱子剩余体积为j时所能装入的最大体积
dp[j]=max(dp[j],dp[j-volume]+volume); //
}
}
cout<<v-dp[v]<<endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;
int n,t,a,b;
int x,y,maxn = -1,ans = INF;
int num[MAXN][MAXN];
int main()
{
scanf("%d",&n);
memset(num,1,sizeof(num));
for(int i = 1; i <= n; i ++)
num[i][i] = 0;
while(scanf("%d%d%d",&x,&y,&t) == 3)
num[x][y] = num[y][x] = t;
// floyd算法,多源最短路
for(int k = 1; k <= n;k ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
num[i][j] = min(num[i][j],num[i][k] + num[k][j]);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
{
maxn = -1;
for(int k = 1; k <= n; k ++)
maxn = max(min(num[i][k],num[k][j]),maxn); // 最短的里面取出来最大的
if(maxn < ans && i != j)
ans = maxn,x = i,y = j;
}
printf("%d %d\n",x,y);
return 0;
}
给出邻接矩阵,要求求最小生成树的值。链接
注意这里的dist矩阵并不是某起点到其余点的距离,而是集合U到集合V的点的较小距离。
因而不像kruskal算法那样更新距离:
if (!visit[j]&&dis[j]>dis[pos]+map[pos][j]) {
dis[j]=dis[pos]+map[pos][j]; // 更新dis
}
#include
#include
#define inf 99999999
int map[1010][1010],dis[1010],book[1010];
int main()
{
int n,a,b,c,i,j,k,min;
int count,sum;
while(scanf("%d",&n)!=EOF) // 输入结点数
{
count=sum=0;
memset(book,0,sizeof(book));
// 初始化邻接矩阵
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=inf;
}
// 邻接矩阵赋值
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&a);
if(a<map[i][j])
{
map[i][j]=a;
map[j][i]=a;
}
}
// 记录第一个点到其他点的距离
for(i=1;i<=n;i++)
dis[i]=map[1][i];
book[1]=1; // 访问数组
count=1;
// 思路:
/*初始化集合U只包含起点,V包含其余所有点。 从起点开始,找离当前点最近的点加入集合U中,
并从集合V中移除,标记已访问; 重复以上步骤,直至集合V空
*/
while(count<n)
{
min=inf;
for(i=1;i<=n;i++) // 对n个点遍历 ,找出最近的点
{
if(book[i]==0&&dis[i]<min) // 若该点未访问,且距离更小则更新
{
min=dis[i]; // 更新距离
j=i; // 记录最近的点的位置
}
}
book[j]=1; // 移除该点,即标记为已访问
count++;
sum+=dis[j];
for(k=1;k<=n;k++)
{
if(book[k]==0&&dis[k]>map[j][k]) // 该点未访问过,且距离更小则更新
dis[k]=map[j][k]; // 更新距离
}
}
printf("%d\n",sum); // 输出最小生成树的值
}
return 0;
}
题目链接
**
最小生成树prim算法步骤
1.初始化邻接矩阵,对角线全0,连接不到则为inf
2.把起点加入集合U
3.for i 1 -> n : // 遍历剩下n-1个点
for j 0 -> n : // 遍历集合V,寻找最近的点
寻找集合V中点dist[]最小的值,记为min,并标记该点index
把最小点加入集合U中,累加该距离
for k 0 -> n : // 遍历集合U,更新集合U到集合V的距离
dist[k]=min(dist[k],map[index][k] ); // dist[i]代表未访问路径中,集合U和集合V中距离最小的两点距离
#include
#include
using namespace std;
// 11.30
int map[100][100];
// 最小生成树问题
int main(){
// 输入结点数n
int n;
cin>>n;
// 输入邻接矩阵map
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>map[i][j];
}
}
// 创建dist矩阵,dist为当前
int dist[100];
for(int i=0;i<n;i++){
dist[i]=map[0][i];
}
// prim算法实现---加点法,其实是n个点里面不断加入边
/* 对于某一点,选定起点a后(集合U),遍历集合V,找到最近的b点加入
标记点b为已经访问(加入集合U),更新dist矩阵,dist矩阵为起点到其他点的最近距离;
遍历集合V,找到集合V中离集合U内的点最近的距离点c,加入集合U中,再更新dist矩阵
*/
int vis[100];
for(int i=0;i<n;i++)
vis[i]=0;
vis[0]=1;
int sum=0;
for(int i=0;i<n-1;i++){ // 对n个点遍历,
int min=0x3f3f3f3f;
int index=0;
for(int j=0;j<n;j++){ // 对集合V遍历 ,找到集合V中最近的且未访问过的点
if(vis[j]==0&&dist[j]<min){
min=dist[j];
index=j;
}
}
vis[index]=1; // 加入集合U
sum+=dist[index];
// 更新dist
for(int k=0;k<n;k++){
if(vis[k]==0&&dist[k]>map[index][k])
dist[k]=map[index][k];
}
}
cout<<sum;
}
注意对于大数余法,我们有定律:(a+b)%c=((a%c)+(b%c))%c
,因而我们常用以下形式来计算:
int add(int a, int b) { return (a + b) % MOD;}
因而以下代码结果是一样的
#include
using namespace std;
int MOD;
int add(int a, int b) { return (a + b) % MOD;}
int main(){
int a,b;
while(cin>>a>>b>>MOD)
cout<
代码如下:
class Solution {
const int MOD = 1e9+7;
int add(int a, int b) { return (a + b) % MOD; }
public:
int knightDialer(int N) {
int dp[5111][10]; // dp[i][j]表示走i步,当前处于第j位的走法有多少种
for(int i=0;i<10;i++)
dp[0][i] = 1;
for(int t=1;t<N;t++) {
dp[t][0] = add(dp[t-1][4], dp[t-1][6]);
dp[t][1] = add(dp[t-1][6], dp[t-1][8]);
dp[t][2] = add(dp[t-1][7], dp[t-1][9]);
dp[t][3] = add(dp[t-1][4], dp[t-1][8]);
dp[t][4] = add(dp[t-1][0], add(dp[t-1][9], dp[t-1][3]));
dp[t][5] = 0;
dp[t][6] = add(dp[t-1][1], add(dp[t-1][7], dp[t-1][0]));
dp[t][7] = add(dp[t-1][2], dp[t-1][6]);
dp[t][8] = add(dp[t-1][1], dp[t-1][3]);
dp[t][9] = add(dp[t-1][2], dp[t-1][4]);
}
int ans = 0;
for(int i=0;i<10;i++)
ans = add(ans, dp[N-1][i]);
return ans;
}
};