这些题挺折磨我的
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比较部分犯了第一道题说的错误,也是很长时间才看出来。
总体来看,思路大体上没错,主体部分写的没大错,就是这些小细节,造成了通过不了。我想,我应该有这样的思维,看到错误的部分,顺便把上下跟这个错误有关系的部分也看了,还有,不要图省事,要么能把边值写上就写上,要么必须记住,忘了这样的细节,想要以后再发现比第一次就想到还难;