30天算法突破计划——Day2

AC1

Problem,求用N张邮票且只有K种的情况下可以取得的最大连续值

思路

使用DFS+DP的做法,在DFS中搜索每一位的取值,在DP中去搜索在这个取值的情况下能够取到的最大的最大连续数,并以此+1作为下一个数的上界,

代码部分

0 数据结构
int ans[20]; // 是我们最终的
int a[20];
1 DP
int dp(int t)
{
    int f[N];
    f[0] = 0;
    for (int i = 1; i <= a[t]*n; i++) f[i] = N;
    // 赋一个比较大的数取给f[i]
    for (int i = 1; i <= t; i++)
    {
        for (int  j = a[i]; j <= a[t]*n; j++)
        {
            f[j] = min(f[j],f[j-a[i]]+1);
        }
    }
    for (int i = 1; i <= a[t]*n; i++)
    {
        if(f[i]>n) return i-1;
    }
    return a[t]*n;
    // 取得一个可能的结果
}
DFS
void DFS(int t,int mx)
{
    if(t==k+1)
    {
        // 如果已经查找完了所有的数,那么进行答案的更新
        if(mx > maxn)
        {
            maxn = mx;
            // 更新最大值
            for (int i = 1; i <= t-1; i++) ans[i] = a[i];
        }
        return;
    }
    for (int i = a[t-1] + 1; i <= mx + 1 ; i++)
    {
        // 通过dp我们可以得到在mx之前的数都是连续可取的,所以我们的下界是a[t-1]+1.上界是mx+1
        a[t] = i;
        int x = dp(t);
        DFS(t+1, x);
        // 去搜索下一个数
    }
}
ALL
#include<iostream>
#define N 50010
using namespace std;
int n,maxn;
int k;
int ans[20];
int a[20];
int dp(int t)
{
    int f[N];
    f[0] = 0;
    for (int i = 1; i <= a[t]*n; i++) f[i] = N;
    // 赋一个比较大的数取给f[i]
    for (int i = 1; i <= t; i++)
    {
        for (int  j = a[i]; j <= a[t]*n; j++)
        {
            f[j] = min(f[j],f[j-a[i]]+1);
        }
    }
    for (int i = 1; i <= a[t]*n; i++)
    {
        if(f[i]>n) return i-1;
    }
    return a[t]*n;
    // 取得一个可能的结果
}
   // 进行Dp去查找每个可能的结果,如果这个数可以在有限的数内被取到,那么就是可行的
void DFS(int t,int mx)
{
    if(t==k+1)
    {
        // 如果已经查找完了所有的数,那么进行答案的更新
        if(mx > maxn)
        {
            maxn = mx;
            // 更新最大值
            for (int i = 1; i <= t-1; i++) ans[i] = a[i];
        }
        return;
    }
    for (int i = a[t-1] + 1; i <= mx + 1 ; i++)
    {
        // 通过dp我们可以得到在mx之前的数都是连续可取的,所以我们的下界是a[t-1]+1.上界是mx+1
        a[t] = i;
        int x = dp(t);
        DFS(t+1, x);
        // 去搜索下一个数
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    DFS(1,0);
    for (int i = 1; i <= k; i++)
    {
        printf("%d ",ans[i]);
    }
    printf("\n");
    printf("MAX=%d",maxn);
    return 0;
    
}

AC2

Problem,单源最短路径

思路

在这里我们使用狄杰斯特拉算法,

What is dijkstra?

从起点出发,不断向外拓展,更新它相邻的点距离的,每次更新再将更新后的点加入到集合中去。

The Code

#include<iostream>
#include<string.h>
#include<queue>
#define N 500010
#define INF 1515870810
using namespace std;
struct egde
{
  int dis;
  int next;
  int to;
}E[N];
// 标准邻接表
struct  node
{
  int dis,num;
  inline bool operator < (const node&x)const
  {
    return dis>x.dis;
  }
};
// 大根堆,使用大根堆堆dijkstra进行优化
int cnt;
int n,m,s,vis[N],dis[N];
int Head[N];
void add(int x,int y,int z)
{
  E[++cnt].next = Head[x];
  E[cnt].to = y;
  E[cnt].dis = z;
  Head[x] = cnt;
}
// 增加我们的边
priority_queue<node>q;
void dijkstra()
{
  dis[s] = 0;
  q.push((node){0,s});
  while (!q.empty())
  {
    node x = q.top();
    q.pop();
    int temp = x.num;
    if(vis[temp]) continue;
    vis[temp] = 1;
    for (int i = Head[temp]; i; i = E[i].next)
    {
      int v = E[i].to;
      if(dis[v] > E[i].dis + dis[temp])
      {
        dis[v] = E[i].dis + dis[temp];
          q.push((node){dis[v],v});
      }
    }
  }
  
}
int main()
{
  scanf("%d%d%d",&n,&m,&s);
  int u,v,w;
  memset(dis,INF,sizeof(dis));
  for (int i = 0; i < m; i++)
  {
    scanf("%d%d%d",&u,&v,&w);
      if(u!=v)
    add(u,v,w);
  }
  dijkstra();
  for (int i = 1; i <= n; i++)
  {
      if(dis[i]==INF) printf("%d ",2147483647);
      else printf("%d ",dis[i]);
  }
  return 0;
}

AC3

Problem,有向图单源最短路径加上多源同终点最短路径

思路

单源最短路径我们可以继续使用dijkstra算法进行处理,在多源同终点最短路径中我们可以使用反向建图的方式,转化为单源最短路径的方式进行处理

Code

#include<iostream>
#include<string.h>
#include<queue>
#define N 500010
#define INF 1515870810
using namespace std;
struct egde
{
  int dis;
  int next;
  int to;
}E[N];
// 标准邻接表
struct  node
{
  int dis,num;
  inline bool operator < (const node&x)const
  {
    return dis>x.dis;
  }
};
// 大根堆,使用大根堆堆dijkstra进行优化
int cnt;
int n,m,vis[N],dis[N];
int Head[N];
void add(int x,int y,int z)
{
  E[++cnt].next = Head[x];
  E[cnt].to = y;
  E[cnt].dis = z;
  Head[x] = cnt;
}
// 增加我们的边
priority_queue<node>q;
void dijkstra(int s)
{
  memset(dis,INF,sizeof(dis));
  dis[s] = 0;
  q.push((node){0,s});
  while (!q.empty())
  {
    node x = q.top();
    q.pop();
    int temp = x.num;
    if(vis[temp]) continue;
    vis[temp] = 1;
    for (int i = Head[temp]; i; i = E[i].next)
    {
      int v = E[i].to;
      if(dis[v] > E[i].dis + dis[temp])
      {
        dis[v] = E[i].dis + dis[temp];
          q.push((node){dis[v],v});
      }
    }
  }
}
// 标准狄杰斯特拉算法
int main()
{
  scanf("%d%d",&n,&m);
  int u,v,w;
  for (int i = 0; i < m; i++)
  {
      scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);
      add(v+n, u+n, w);
     // 反向建图
  }
  dijkstra(1);
  long long ans = 0;
  for (int i = 2; i <= n; i++)
  {
      ans += dis[i];
  }
  dijkstra(1+n);
  // 反向单源最短路径
  for (int i = 2+n; i <= 2*n; i++)
  {
    ans += dis[i];
  }
  printf("%lld",ans);
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值