题目链接 P3959 宝藏
一个小小的开头
对于这道题本蒟讲讲自己的一些想法:分别是20分做法、40分做法、70分做法(暂时还没做出,会补上的)、和100分做法。
其实现在的我很是不明白当初(去年高二时)参加noip时这一道题为什么没有拿到45分?我真的搞不懂当初自己为啥为那么愚蠢(也许现在也差不多)n明明很小(当初没怎么接触过状压,所以就不晓得,这情有可原)而且明明很多边是没用的!但我还因为考场一紧张就不记得dij(我也不记得当时自己是不是想的prim)然后就觉得可以用floyd求任意点的最短路(可我当时不会dij也应该会SPFA啊,当时自己还特喜欢用SPFA)。然后因为45分以内的边长是相同的,所以我们就可以去乱搞一下,但我tema还是只得了25分!!!当时的自己是有多菜!(可能现在也好不到哪去)
20分做法
个人觉得这是给一些不知道最短路是啥的OIer的分数,求一下树上的路径,然后因为边长都一样所以最后答案就是每个点到跟节点深度*边长值就行了。不过还要以每一个节点为跟节点去算一次,球个最小值。很容易写,就没写代码了。
40分做法
根据20分做法带来的启发,我们只要对这个图以某一个点为起始点跑最短路(不管是dij还是floyd还是spfa都可以,只是dij将所有的都可以一次性求出来)然后对于没一个点我们就可像上述20分的做法去求答案了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,m,ans=0x3f3f3f3f,sum,vv,pos;
int a[15][15],dist[15],vis[15];
inline int read() {
int x=0,w=1;char ch;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
void dij(int s) {
memset(vis,0,sizeof(vis));sum=0;
memset(dist,0x3f,sizeof(dist));
for(register int i=1;i<=n;++i) dist[i]=a[s][i];
vis[s]=1;
for(register int i=1;i<=n-1;++i) {
int minn=0x3f3f3f3f;
for(register int j=1;j<=n;++j)
if(!vis[j]&&dist[j]<minn) minn=dist[j],pos=j;
vis[pos]=1;sum=sum+dist[pos]*vv;//边求就边计算答案了
for(register int j=1;j<=n;++j)
if(!vis[j]&&dist[j]>a[pos][j]+dist[pos])
dist[j]=min(dist[j],dist[pos]+a[pos][j]);
}
}
int main() {
n=read();m=read();
memset(a,0x3f,sizeof(a));
for(register int i=1;i<=m;++i) {
int u=read(),v=read(),w=read();vv=w;
a[u][v]=a[v][u]=1;
}
for(register int i=1;i<=n;++i) {
prim(i);
ans=min(ans,sum);
}
cout<<ans<<endl;
return 0;
}
70分做法
暂时还没作出,会尽快补上,请谅解。
100分做法
网上很多大佬都讲了,贴一个博客吧。https://www.luogu.org/blog/dazade8/solution-p3959