习题日常第二十四练

1寻找道路(题目链接

这个题有点绕。我们可以通过从终点出发,将已知边反向,用bfs搜,找到可以直接到达终点的点。再通过对每个点遍历,若这个点不能到终点,则反向后的所有与它相连点都不能到。但是注意,此时删点有后效性,需要用两个数组完成。最后在所有合法点上再跑一遍迪杰斯特拉算法求最短路即可。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#include<sstream>
#define  ll long long int
const ll mod=998244353;
using namespace std;
ll b[100010],a[100010],vis[100010],pis[100010],dis1[100010],dis[100010],tot=0,pot=0;
priority_queue<pair<ll,ll> >p;
deque<ll> q;
struct node
{
    ll w,to,next;
}tz[800010],pz[800010];
void add1(ll x,ll y)
{
    tz[++tot].w=1;
    tz[tot].to=y;
    tz[tot].next=a[x];
    a[x]=tot;
}
void add2(ll x,ll y)
{
    pz[++pot].w=1;
    pz[pot].to=y;
    pz[pot].next=b[x];
    b[x]=pot;
}
int main()
{
    ios::sync_with_stdio(false);
    ll i,j,n,m,s,t;
    cin>>n>>m;
    memset(vis,0,sizeof(vis));
    memset(pis,0,sizeof(pis));
    for(i=0;i<=n;i++)
    {
        a[i]=b[i]=-1;
        dis[i]=dis1[i]=1e12;
    }
    for(i=0;i<m;i++)
    {
        ll x,y;
        cin>>x>>y;
        if(x!=y)
        {
        add1(x,y);
        add2(y,x);
        }
    }
    cin>>s>>t;
    q.push_back(t);
    dis1[t]=0;
    while(!q.empty())
    {
        ll x=q.front();
        q.pop_front();
        for(i=b[x];i!=-1;i=pz[i].next)
        {
           if(!pis[pz[i].to])
           {
               dis1[pz[i].to]=dis1[x]+1;
               q.push_back(pz[i].to);
               pis[pz[i].to]=1;
           }
        }
    }
    memcpy(vis,dis1,sizeof(dis1));
   for(i=1;i<=n;i++)
   {
       if(vis[i]>=1e12)
       for(j=b[i];j!=-1;j=pz[j].next)
       {
          if(vis[pz[j].to]!=1e12)
            vis[pz[j].to]=1e12;
       }
   }
  q.push_back(s);
   dis[s]=0;
  while(!q.empty())
   {
       ll x=q.front();
       q.pop_front();
       for(i=a[x];i!=-1;i=tz[i].next)
       {
           if(vis[tz[i].to]!=1e12)
           {
               dis[tz[i].to]=dis[x]+1;
              q.push_back(tz[i].to);
              vis[tz[i].to]=1e12;
           }
       }
   }
   if(dis[t]==1e12)
    cout<<"-1";
   else
    cout<<dis[t];
  return 0;
}

2 n的约数(题目链接

这个题用dfs搜,对于一个数,可以拆成素数的幂次之积,约数个数则为(幂次+1)之积。但是注意数据特别大,需要及时判断是否超过已知数字大小(用除法判)。代码如下。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#include<sstream>
#define  ll long long int
const ll mod=998244353;
using namespace std;
ll n,m,a[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51},ans=0;
void dfs(ll pos,ll len,ll zi,ll sum)
{
    if(sum>n)
        return;
    if(sum<=n)
      ans=max(ans,zi);
    ll res=1,i;
    for(i=1;i<=len;i++)
    {
        res*=a[pos];
        dfs(pos+1,i,zi*(i+1),sum*res);
        if(sum>n/res)
            break;
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    ll i,j,s,t;
    cin>>m;
    for(i=0;i<m;i++)
    {
        cin>>n;
        ans=0;
        dfs(1,32,1,1);
        cout<<ans<<endl;
    }

  return 0;
}

3经商(题目链接

这个题比较简单,思路非常的清晰。先用并查集看有哪些人与小d认识,把认识的人的信息存入数组或者结构体中,然后用一个简单的背包dp就解决了。代码如下。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#include<sstream>
#define  ll long long int
const ll mod=998244353;
using namespace std;
ll n,m,fa[100010],c,a[100010],b[100010],dp[100010];
struct node
{
    ll v,w;
}p[100010];
ll fin(ll x)
{
    if(fa[x]==x)
        return x;
    else
        return fa[x]=fin(fa[x]);
}
void jia(ll x,ll y)
{
    x=fin(fa[x]);
    y=fin(fa[y]);
    if(x!=y)
    {
        fa[x]=fa[y];
    }
}
bool pan(ll x,ll y)
{
    x=fin(fa[x]);
    y=fin(fa[y]);
    if(x==y)
        return true;
    else
        return false;
}
int main()
{
    ios::sync_with_stdio(false);
    ll i,j,s,t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>c;
        for(i=0;i<=n;i++)
            fa[i]=i;
        for(i=1;i<n;i++)
        {
            cin>>a[i+1]>>b[i+1];
        }
        for(i=0;i<m;i++)
        {
            ll x,y;
            cin>>x>>y;
            jia(x,y);
        }
        j=0;
        memset(dp,0,sizeof(dp));
        for(i=2;i<=n;i++)
        {
            if(pan(1,i))
            {
                p[j].w=a[i];
                p[j].v=b[i];
                j++;
            }
        }
        m=j;
        for(i=0;i<=c;i++)
        {
            if(p[0].w<=i)
            {
                dp[i]=p[0].v;
            }
        }
        for(i=1;i<m;i++)
        {
            for(j=c;j>=p[i].w;j--)
            {
                dp[j]=max(dp[j],dp[j-p[i].w]+p[i].v);
            }
        }
        cout<<dp[c]<<endl;
    }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值