俱乐部训练题8

这些题挺折磨我的

B3647 【模板】Floyd - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include

using namespace std;

int main()
{
    long long map[105][105],n,m,k,i,j,visit[105],dist[105],u,v,w,start,next;
    long long maper[105][105],num;
    long long mmm=0x7FFFFFFF,mi;
    cin>>n>>m;

    for(i=1;i<=n;i++)
    {

        for(j=1;j<=n;j++)
        {
            map[i][j]=mmm;

        }
    }
    for(i=1;i<=n;i++)
    {

            map[i][i]=0;

    }
        while(m--)
    {
        cin>>u>>v>>w;
        map[u][v]=w;
        map[v][u]=w;
    }
    for(k=1;k<=n;k++)
    {
        for(i=1;i<=n;i++)
        {
            visit[i]=0;
            dist[i]=mmm;
        }
        visit[k]=1;
         dist[k]=0;
        start=k;
        num=n-1;
        while(num--)
        {
            mi=mmm;
            for(i=1;i<=n;i++)
            {
                dist[i]=min(dist[i],dist[start]+map[start][i]);
                if(visit[i]==0&&dist[i]

这是使用了邻接矩阵的做法,没有使用vector,这不是floyd算法,而是dijkstra算法,注意使用min函数的那一行,有一次换成了if来实现同样的功能,但是if的大括号把下面的if给包住了,这会造成,如果一开始我把从第一个start到所有点的dist[i]都求出来了,而且第二个start得到的dist[start]+map[start][i]都比第一个start求的dist[i]大,那么就不会更新nex,也就是不会再去找第三个最近点了。如果放在一个比较大的题目里,脑子本来就很乱了,再加上大括号用错跟正确用法看上去差别很小,对于我来说那就几乎不可能看出来这里错了。

P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include
#include
#include
using namespace std;
struct edge
{
    int to;
    int dis;
    int next;
};
struct node
{
    int dis;
    int pos;
    bool operator<(const node &x)const
    {
        return x.dis>n>>m>>s;
    for(int i=1;i<=n;i++)
        dist[i]=0x7fffffff;
    for(register int i=0;i>u>>v>>d;
        cnt++;
        e[cnt].dis=d;
        e[cnt].to=v;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
std::priority_queue q;
dist[s]=0;
q.push((node){0,s});
   while(!q.empty())
    {

      node tmp=q.top();
      q.pop();
      int x=tmp.pos,d=tmp.dis;
      if(vis[x])
        continue;
      vis[x]=1;
      for(int i=head[x];i;i=e[i].next)
      {
          int y=e[i].to;
          if(dist[y]>dist[x]+e[i].dis)
          {
               dist[y] = dist[x] + e[i].dis;
               if(!vis[y])
               {
                   q.push((node){dist[y],y});
               }
          }
      }
    }
    for(int i=1;i<=n;i++)
    {
        cout<

这是使用了优先队列,这里注意,这里if(dist[y]>dist[x]+e[i].dis)的大括号包住了下面的q.push,其实,无论包不包住q.push都是合理的,因为这是优先队列,如果就按原来的代码来,在第一个点s遍历了它的所有终点后,选出来的第二个点是第一近点,第一近点再遍历它所有的终点,如果第二近点是由s直接到的,那么就算第二次遍历的时候不把这个点push到队列里也没事,因为在第一次遍历的时候已经放进去了,如果第二近点是由s到第一近点再到的,那么两种写法都会将这个点push进来。这个优先队列写法可以将大括号包住q.push,但是上一道题不能包住nex,因为上一道题包住所有的nex是为了从中找出来dist最小的nex做下一个第多少近点,在第二近点遍历时,一开始s点遍历的结果只参与了dist的比较,但是(如果大括号括住nex)并不参与新生成的dist[1]到dist[n]的比较,这会造成可能在dist[y]<=dist[x]+e[i].dis的情况下部分dist[i]缺失,一旦第二近点的第dist缺失,就找不到第二近点了,这道题呢这种情况不会出现,因为这是优先队列,在第一近点遍历所有点之后,一开始s遍历的结果还在队列里,还参与新生成的dist[1]到dist[n]的比较。

P2661 [NOIP2015 提高组] 信息传递 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include
using namespace std;
int min(int x,int y)
{
    if(x>n;
    for(int i=1;i<=n;i++)
    {
        cin>>e[i].to;
    }
    for(i=1;i<=n;i++)
    {
        if(e[i].cnt!=0) continue;

        ctt=1;
        a++;
        for(j=i;e[j].cnt==0;j=e[j].to)
        {
            e[j].cnt=ctt;
            e[j].time=a;
            ctt++;
        }
        if(e[j].time==a)
        {
            len=ctt-e[j].cnt;

        m=min(len,m);
        }
    }
    cout<

这个题比较简单

P1144 最短路计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include 
#include
#include
using namespace std;
vectorve[1000006];
int visit[1000006],dist[1000006],ans[1000006];
int main()
{
    int n,m,u,v;
    cin>>n>>m;
    for(int i=0;i<=1000006;i++)
    {
        dist[i]=0x7fffffff;
    }
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        ve[u].push_back(v);
        ve[v].push_back(u);
    }
    queuequ;
    qu.push(1);
    visit[1]=1;
    ans[1]=1;
    dist[1]=0;
    while(!qu.empty())
    {
        int cur=qu.front();
        qu.pop();

        for(int i=0;i

权重相同,那么可以减少一般dijkstra写法内容,注意,运行到某一阶段,对于队列中的首点来说,它所连的所有visit=0的点s并不都是一样的,对于有的s来说,从原点到这个首点(带有首点的ans值x代表的所有x条路径)再到s的路不是最短的,而是最短+1的,对于别的的s来说,就是最短的,如何区分?就用dist值区分

P8794 [蓝桥杯 2022 国 A] 环境治理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include
#define abcd

using namespace std;
long long n,q,d[103][103],l[103][103],i,ma,j,k,nex,start,day;
long long dist[103][103],visit[103][103];
long long ans;
long long le,ri,mid;
long long dd[103][103];
long long min(long x,long y)
{
    if(xl[i][j])
             {
                dd[i][j]--;
                dd[j][i]--;
             }
         }
     }
     if(dayn!=0)
     for(i=1;i<=n;i++)
     {
         for(j=1;j<=n;j++)
         {
             if(dd[i][j]>=l[i][j]+dayn)
             {
                 dd[i][j]-=dayn;
                 dd[j][i]-=dayn;
             }
             else
             {
                 dd[i][j]=l[i][j];
                 dd[j][i]=l[j][i];
             }
         }
     }


    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            dist[i][j]=0x7fffffff;
            visit[i][j]=0;
        }
        dist[i][i]=0;
        visit[i][i]=1;
        start=i;
        for(j=1;j<=n;j++)
        {
            ma=0x7fffffff;
            for(k=1;k<=n;k++)
            {
                    dist[i][k]=min(dist[i][k],dist[i][start]+dd[start][k]);
                    if(dist[i][k]>n>>q;
    for(i=1;i<=n;i++) for(j=1;j<=n;j++) cin>>d[i][j];
    for(i=1;i<=n;i++) for(j=1;j<=n;j++) cin>>l[i][j];
    le=0;
    ri=100005*n+1;
    while(le!=ri)
    {

        mid=(le+ri)/2;
        if(calc(mid)<=q)
        {
            ri=mid;
        }
        else
        {
            le=mid+1;
        }
    }

    if(le==100005*n+1)
    {
        cout<<-1;
        return 0;
    }
    cout<

这道题大意明显,二分法较容易使用,困难的地方在于细节,或者说坑多。

calc函数要多次被调用,每次调用,自变量day不同所以每次开始所有路的权值必须跟题目输入的一样,这可以通过新建一个不同于d[i][j]的dd[i][j]来表示,但是注意 dd[i][j]-=dayn和dd[j][i]-=dayn不要写成dd[i][j]=d[i][j]-dayn和dd[j][i]=d[j][i]-dayn,同时如果写的时候发现了这个错误,一定要把包含它的那个if里的条件也该了,如果这也发现了,那一定再记得把上面的dayr部分的if条件和包含的内容也改了,我写的时候发现了第一个错误,改了,然后就没看条件,半天以后发现条件错了,改了,然后没看dayr部分同样的错误,最后又半天改了。

同时别忘了dayr和dayn等于0的情况,我一开始记得,后来想着先把主体部分写了再说,结果忘了,很长时间才发现,这很折磨人,一旦不赶紧写上dayr和dayn的边值情况,忘了,那以后想再发现它就不是容易的事情了。

同时我在dist比较部分犯了第一道题说的错误,也是很长时间才看出来。

总体来看,思路大体上没错,主体部分写的没大错,就是这些小细节,造成了通过不了。我想,我应该有这样的思维,看到错误的部分,顺便把上下跟这个错误有关系的部分也看了,还有,不要图省事,要么能把边值写上就写上,要么必须记住,忘了这样的细节,想要以后再发现比第一次就想到还难;

你可能感兴趣的:(算法)